473,473 Members | 2,080 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

is int(round(val)) safe?

I realize this probably a stupid question, but...is it safe to
round to the nearest integer by using int(round(val))?

I suspect it is fine, but wanted to be sure that weird floating point
representation on some platform might make it unsafe there (i.e. get the
wrong value due to the floating point value being an approximation) and
if so, is there a Better Way).

-- Russell
Jul 18 '05 #1
11 2502
Russell E. Owen wrote:
I realize this probably a stupid question, but...is it safe to
round to the nearest integer by using int(round(val))?
Define "safe".
I suspect it is fine, but wanted to be sure that weird floating point
representation on some platform might make it unsafe there (i.e. get the
wrong value due to the floating point value being an approximation) and
if so, is there a Better Way).


Since round() returns an integer, and since (ignoring really
large integers, since I doubt you're concerned about them
here) floating point values can handle *integer* values
perfectly well, there's no reason it shouldn't do what you
want.

The problem* with floating point is inaccurate representation
of certain _fractional_ values, not integer values.

-Peter

* Well, _one_ of the problems. ;-)
Jul 18 '05 #2
Peter Hansen wrote:
Since round() returns an integer


Just to clarify in case anyone else misreads this, I belive the intent
here was to say that round(f) -- that is, round with only a single
argument -- returns a floating point number with no fractional component
after the decimal point. The result is still a float, not an int though:
round(3.14159265359) 3.0 round(3.14159265359, 2)

3.1400000000000001

I think the intent was clear from the rest of the post, but I figured it
wouldn't hurt to clarify this for any newbies who misread it like I did.

Steve
Jul 18 '05 #3
Steven Bethard wrote:
Peter Hansen wrote:
Since round() returns an integer


Just to clarify in case anyone else misreads this, I belive the intent
here was to say that round(f) -- that is, round with only a single
argument -- returns a floating point number with no fractional component
after the decimal point. The result is still a float, not an int though:
>>> round(3.14159265359) 3.0 >>> round(3.14159265359, 2)

3.1400000000000001

I think the intent was clear from the rest of the post, but I figured it
wouldn't hurt to clarify this for any newbies who misread it like I did.


All true.

I wonder if it would be appropriate to say something along
the lines of '''round() returns an integer, but not an "int".'''

Obviously the mathematicians will have something to say about
this. In computers, 1.0 may not be an integer data type, but
I think in math it's still considered an integer. I am most
definitely not going to claim authority in this area, however,
since as an engineer I consider 1.0 and 1 merely "equal to a
first approximation". <wink>

-Peter
Jul 18 '05 #4
[Peter Hansen]
....
I wonder if it would be appropriate to say something along
the lines of '''round() returns an integer, but not an "int".'''
Well, round() is a 2-argument function, whose second argument defaults
to 0. It's quite defensible to say that round returns an integer
value when the second argument is 0.
Obviously the mathematicians will have something to say about
this. In computers, 1.0 may not be an integer data type, but
I think in math it's still considered an integer.
Depends on which mathematician you're talking to. The integer 1 is
most often defined as the set containing the empty set, or, in a
suitably restricted set theory, with the set of all sets containing 1
element (which is a proper class in most set theories). A real, OTOH,
is a godawful construction that Americans typically don't learn until
after they've completed "calculus" and gone on to "analysis".

So, instead of talking to mathematicians, I advise talking to me
<wink>. Yes, 1.0 is an integer! In fact, so is 1.9998e143: all
sufficient large floats are exact integers. That's why, e.g.,
math.ceil() and math.floor() return arguments like 1.9998e143
unchanged -- such inputs are already integers.
I am most definitely not going to claim authority in this area, however,
since as an engineer I consider 1.0 and 1 merely "equal to a
first approximation". <wink>


If they differ at all, then e = 1.0 - 1 must be nonzero. Since it
isn't, they're identical <wink>.
Jul 18 '05 #5
On Mon, 22 Nov 2004 15:58:54 -0500, Peter Hansen <pe***@engcorp.com> wrote:
Russell E. Owen wrote:
I realize this probably a stupid question, but...is it safe to
round to the nearest integer by using int(round(val))?
Define "safe".
I suspect it is fine, but wanted to be sure that weird floating point
representation on some platform might make it unsafe there (i.e. get the
wrong value due to the floating point value being an approximation) and
if so, is there a Better Way).


Since round() returns an integer, and since (ignoring really
large integers, since I doubt you're concerned about them
here) floating point values can handle *integer* values
perfectly well, there's no reason it shouldn't do what you
want.

The problem* with floating point is inaccurate representation
of certain _fractional_ values, not integer values.


Well, you mentioned really large integers, and I think it's worth
mentioning that you can get inaccurate representation of certain of those
values too. I.e., what you really have (for ieee 754 doubles) is 53 bits
to count with in steps of one weighted unit, and the unit can be 2**0
or 2**otherpower, where otherpower has 11 bits to represent it, more or less
+- 2**10 with an offset for 53. If the unit step is 2**1, you get twice the range
of integers, counting by two's, which doesn't give you a way of representing the
odd numbers between accurately. So it's not only fractional values that can get
truncated on the right. Try adding 1.0 to 2.0**53 ;-)
2.0**53 9007199254740992.0 2 **53 # just to check 9007199254740992L 2.0**53 + 1.0 9007199254740992.0 2 **53 + 1 # just to check 9007199254740993L

The float gets rounded down, but you can count by two's
2.0**53 9007199254740992.0 2.0**53 +2.0

9007199254740994.0

(2.0**53-1.0 is the last number with a LSB value of 1.0, but you can add 1.0
to that and get an exact 2.0**53 because the unit bit that results is 0 so it
doesn't matter that it's to the right of the new LSB of 2.0**53 (which has a weight of 2.0)).

Another way of thinking about it is that it's not about the accuracy of the numbers,
it's about how far apart the available accurate number representations are and the
choice you have to make if the value you want to represent falls between.

-Peter

* Well, _one_ of the problems. ;-)


Regards,
Bengt Richter
Jul 18 '05 #6
"Russell E. Owen" <ro***@cesmail.net> wrote in message news:<ro*************************@gnus01.u.washing ton.edu>...
I realize this probably a stupid question, but...is it safe to
round to the nearest integer by using int(round(val))?

I suspect it is fine, but wanted to be sure that weird floating point
representation on some platform might make it unsafe there (i.e. get the
wrong value due to the floating point value being an approximation) and
if so, is there a Better Way).


Yes, int(round(val)) is safe. The only concern is avoiding errors in
"val" itself. For example,
val 3.4999999999999996 # Should have been exactly 3.5 int(round(val))

3 # Should have been 4
Jul 18 '05 #7
Tim Peters wrote:
[Peter Hansen]
....
I wonder if it would be appropriate to say something along
the lines of '''round() returns an integer, but not an "int".'''

Well, round() is a 2-argument function, whose second argument defaults
to 0. It's quite defensible to say that round returns an integer
value when the second argument is 0.

Obviously the mathematicians will have something to say about
this. In computers, 1.0 may not be an integer data type, but
I think in math it's still considered an integer.

Depends on which mathematician you're talking to. The integer 1 is
most often defined as the set containing the empty set, or, in a
suitably restricted set theory, with the set of all sets containing 1
element (which is a proper class in most set theories). A real, OTOH,
is a godawful construction that Americans typically don't learn until
after they've completed "calculus" and gone on to "analysis".

And most of them don't understand even then. What I want to know is why
doesn't Python 2.4 have a speedy implementation of infinite-dimensional
Banach spaces?
So, instead of talking to mathematicians, I advise talking to me
<wink>. Yes, 1.0 is an integer! In fact, so is 1.9998e143: all
sufficient large floats are exact integers. That's why, e.g.,
math.ceil() and math.floor() return arguments like 1.9998e143
unchanged -- such inputs are already integers.

I am most definitely not going to claim authority in this area, however,
since as an engineer I consider 1.0 and 1 merely "equal to a
first approximation". <wink>

If they differ at all, then e = 1.0 - 1 must be nonzero. Since it
isn't, they're identical <wink>.


You can tell this by examining the behavior of something as simple (;-)
as a Python dict:
d = {1.0: "Something", .... 1: "Something else"} d {1.0: 'Something else'}


Python has known for a long time that 1.0 and 1 are the same thing.
Note, however, that I don't believe it's guaranteed that the contents of
d will turn out the same in different Python versions. I suppose Tim
would be able to quote chapter and verse, given his familiarity with
every little implementation detail of the dict.

guaranteed-to-confuse-the-confusable-ly y'rs - steve
--
http://www.holdenweb.com
http://pydish.holdenweb.com
Holden Web LLC +1 800 494 3119
Jul 18 '05 #8
bo**@oz.net (Bengt Richter) writes:
On Mon, 22 Nov 2004 15:58:54 -0500, Peter Hansen <pe***@engcorp.com> wrote:
Russell E. Owen wrote:
The problem* with floating point is inaccurate representation
of certain _fractional_ values, not integer values.


Well, you mentioned really large integers, and I think it's worth
mentioning that you can get inaccurate representation of certain of those
values too. I.e., what you really have (for ieee 754 doubles) is 53 bits
to count with in steps of one weighted unit, and the unit can be 2**0
or 2**otherpower, where otherpower has 11 bits to represent it, more or less
+- 2**10 with an offset for 53. If the unit step is 2**1, you get twice the range
of integers, counting by two's, which doesn't give you a way of representing the
odd numbers between accurately. So it's not only fractional values that can get
truncated on the right. Try adding 1.0 to 2.0**53 ;-)


It's much easier than that to get integer floating point numbers that
aren't correct. Consider:
long(1e70)

10000000000000000725314363815292351261583744096465 219555182101554790400L

I don't know the details on 754 FP, but the FP I'm used to represents
*all* numbers as a binary fraction times an exponent. Since .1 can't
be represented exactly, 1e<anything> will be wrong if you ask for
enough digits.

This recently caused someone to propose that 1e70 should be a long
instead of a float. No one mentioned the idea of making

[0-9]+[eE]+?[0-9]+ be of integer type, and

[0-9]*.[0-9]+[eE][+-]?[0-9]+ be a float. [0-9]+[eE]-[0-9]+ would also
be a float. No simple rule for this, unfortunately.

<mike

--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jul 18 '05 #9
On Tue, 23 Nov 2004 10:50:23 -0600, Mike Meyer <mw*@mired.org> wrote:
bo**@oz.net (Bengt Richter) writes:
On Mon, 22 Nov 2004 15:58:54 -0500, Peter Hansen <pe***@engcorp.com> wrote:
Russell E. Owen wrote:
The problem* with floating point is inaccurate representation
of certain _fractional_ values, not integer values.
Well, you mentioned really large integers, and I think it's worth
mentioning that you can get inaccurate representation of certain of those
values too. I.e., what you really have (for ieee 754 doubles) is 53 bits
to count with in steps of one weighted unit, and the unit can be 2**0
or 2**otherpower, where otherpower has 11 bits to represent it, more or less
+- 2**10 with an offset for 53. If the unit step is 2**1, you get twice the range
of integers, counting by two's, which doesn't give you a way of representing the
odd numbers between accurately. So it's not only fractional values that can get
truncated on the right. Try adding 1.0 to 2.0**53 ;-)


It's much easier than that to get integer floating point numbers that
aren't correct. Consider:
long(1e70)1000000000000000072531436381529235126158374409646 5219555182101554790400L


Yes. I was just trying to identify the exact point where you lose 1.0 granularity.
The last number, with all ones in the available significant bits (including the hidden one)
is 2.**53-1.0
from ut.miscutil import prb
prb(2.**53-1.0) '1111111111111111111111111111111111111111111111111 1111' prb(2.**53-1.0).count('1') 53

the last power of 10 that is accurate is 22, and the reason is plain
when you look at the bits:

10**22 has more than 53 bits but only zeroes to the right of the 53, but 10**23
has a bit to the right.
prb(2.**53-1.0) '1111111111111111111111111111111111111111111111111 1111' prb(10**22) '1000011110000110011110000011001001101110101011001 0010000000000000000000000' prb(1e22) '1000011110000110011110000011001001101110101011001 0010000000000000000000000'

whereas for 23 1e23 != 10**23 prb(10**23) '1010100101101000000101100011111100001010010101111 0110100000000000000000000000' prb(1e23) '1010100101101000000101100011111100001010010101111 0110000000000000000000000000'

The zeroes are eliminated if you use a power of 10/2 or 5, which is always odd prb( 5**22) '1000011110000110011110000011001001101110101011001 001' prb( 5**23) '1010100101101000000101100011111100001010010101111 01101' prb(2.**53-1.0) '1111111111111111111111111111111111111111111111111 1111'

Or in decimal terms:
5.**22 2384185791015625.0 5**22 2384185791015625L 5.**23 11920928955078124.0 5**23 11920928955078125L 2**53 9007199254740992L

so what makes 5.**22 ok is that
5.**22 <= 2.**53-1 True
I don't know the details on 754 FP, but the FP I'm used to represents
*all* numbers as a binary fraction times an exponent. Since .1 can't
be represented exactly, 1e<anything> will be wrong if you ask for
enough digits. I don't understand the "since .1 ..." logic, but I agree with the second
part. Re *all* numbers, if you multiply the fraction represented by the
53 fractional bits of any number by 2**53 you get an integer that you can
consider to be multiplied by 2 ** (the exponent for the fraction - 53),
which doesn't change anything, so I did that, so I could talk about
counting by increments of 1 unit of least precision. But yes, the
usual description is as a fraction times a power of two.

This recently caused someone to propose that 1e70 should be a long
instead of a float. No one mentioned the idea of making

[0-9]+[eE]+?[0-9]+ be of integer type, and

[0-9]*.[0-9]+[eE][+-]?[0-9]+ be a float. [0-9]+[eE]-[0-9]+ would also
be a float. No simple rule for this, unfortunately.

I wrote a little exact decimal module based on keeping decimal exponents and
a rational numerator/denominator pair, which allows keeping an exact representation
of any reasonable (that you might feel like typing ;-) literal, like 1e70, etc., e.g.,
ED('1e70') ED('1.0e70') ED('1e70').astuple() (1, 1, 70) ED('1.23e-45') ED('1.23e-45') ED('1.23e-45').astuple() (123, 1, -47) ED('0.1') ED('0.1') ED('0.1').astuple() (1, 1, -1)
The reason I mention this is not because I think all floating constants should be represented
this way in final code, but that maybe they should in the compiler ast, before code has been
generated. At that point, it seems a shame to have done a premature lossy conversion to platform
floating point, since one might want to take the AST and generate code with other representations.
I.e.,
import compiler
compiler.parse('a=0.1') Module(None, Stmt([Assign([AssName('a', 'OP_ASSIGN')], Const(0.10000000000000001))])) compiler.parse('0.1') Module(None, Stmt([Discard(Const(0.10000000000000001))]))

but from ut.exactdec import ED
ED('0.1') ED('0.1') ED('0.1').astuple() (1, 1, -1)

vs what's represented by the actual floating point bits
ED(0.1,'all') ED('0.10000000000000000555111512312578270211815834 04541015625') ED(0.1,'all').astuple()

(1000000000000000055511151231257827021181583404541 015625L, 1L, -55)

Anyway, tuple is an easy exact possibility for intermediate representation of the number.
Of course, I guess you'd have to tag it as being from a floating point literal or else a code
generator would lose that implicit representation directive for ordinary code generation ...

Regards,
Bengt Richter
Jul 18 '05 #10
[Steve Holden]
,,,
d = {1.0: "Something", ... 1: "Something else"} d {1.0: 'Something else'}


Python has known for a long time that 1.0 and 1 are the same thing.
Note, however, that I don't believe it's guaranteed that the contents of
d will turn out the same in different Python versions. I suppose Tim
would be able to quote chapter and verse, given his familiarity with
every little implementation detail of the dict.


Alas, this chapter hasn't been written yet, let alone the verse. If you do

d[k] = v

when d already has a key equal to k, its associated value is replaced,
but it's really not defined whether the old key is replaced or
retained. All known implementations of Python retain the old key in
this case.

The other *seeming* ambiguity here isn't one: whether, in {a: b, c:
d}, a or c is added first. Python requires "left to right"
evaluation, so that's actually defined -- although this one may be
more clearly defined in Guido's head than by the docs.
Jul 18 '05 #11
Tim Peters wrote:
[Steve Holden]
Note, however, that I don't believe it's guaranteed that the contents of
d will turn out the same in different Python versions.


If you do

d[k] = v

when d already has a key equal to k, its associated value is replaced,
but it's really not defined whether the old key is replaced or
retained. All known implementations of Python retain the old key in
this case.

The other *seeming* ambiguity here isn't one: whether, in {a: b, c:
d}, a or c is added first. Python requires "left to right"
evaluation, so that's actually defined -- although this one may be
more clearly defined in Guido's head than by the docs.


Leading to very interesting results like this:
d = { 1: 'a', 1.0: 'b' }
d

{1: 'b'}

Perhaps unexpected, but clearly explained by the comments above...

-Peter
Jul 18 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: Jody Gelowitz | last post by:
I am trying to find the definition of "Safe Printing" and cannot find out exactly what this entitles. The reason is that I am trying to print contents from a single textbox to no avail using the...
11
by: dee | last post by:
OleDbCommand class like many .NET classes has the following description in its help file: "Thread Safety Any public static (Shared in Visual Basic) members of this type are safe for...
0
by: gm | last post by:
Immediately after generating the Access application from the Source Safe project I get: "-2147467259 Could not use ''; file already in use." If Access database closed and then reopened I get:...
15
by: Laser Lu | last post by:
I was often noted by Thread Safety declarations when I was reading .NET Framework Class Library documents in MSDN. The declaration is usually described as 'Any public static (Shared in Visual...
1
by: johnlim20088 | last post by:
Hi, Currently I have 6 web projects located in Visual Source Safe 6.0, as usual, everytime I will open solution file located in my local computer, connected to source safe, then check out/check in...
1
by: jecheney | last post by:
Hi, Im currently using the following code for reading/writing to a network socket. private StreamReader clientStreamReader; private StreamWriter clientStreamWriter; .... TcpClient tcpClient...
4
by: George2 | last post by:
Hello everyone, Here is Bjarne's exception safe sample, http://www.research.att.com/~bs/3rd_safe.pdf template <class Tclass Safe {
44
by: climber.cui | last post by:
Hi all, Does anyone have experience on the thread-safty issue with malloc()? Some people said this function provided in stdlib.h is not thread- safe, but someone said it is thread safe. Is it...
3
by: =?Utf-8?B?anBhdHJjaWs=?= | last post by:
Don't see any official notice that compiled library dll's loaded in the BIN directory of an asp.net website need to be thread safe, but concurrent visits to the same web site sure bear this out....
1
by: Philss100 | last post by:
Hi, I have been in the process of updating my code with security methods, and I've been learning this from http://msdn.microsoft.com/en-us/library/ms998258.aspx#pagguidelines0001_authorization (or...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.