Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #17207 > unrolled thread
| Started by | Alex Vinokur <alex.vinokur@gmail.com> |
|---|---|
| First post | 2012-02-13 04:41 -0800 |
| Last post | 2012-02-13 12:14 -0800 |
| Articles | 20 on this page of 73 — 19 participants |
Back to article view | Back to comp.lang.c
C/C++ pitfalls related to 64-bits (unsigned long & double) Alex Vinokur <alex.vinokur@gmail.com> - 2012-02-13 04:41 -0800
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Leigh Johnston <leigh@i42.co.uk> - 2012-02-13 12:49 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Alex Vinokur <alex.vinokur@gmail.com> - 2012-02-13 04:59 -0800
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Leigh Johnston <leigh@i42.co.uk> - 2012-02-13 13:07 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Goran <goran.pusic@gmail.com> - 2012-02-13 04:54 -0800
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Alex Vinokur <alex.vinokur@gmail.com> - 2012-02-13 05:00 -0800
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-13 13:27 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Goran <goran.pusic@gmail.com> - 2012-02-13 07:14 -0800
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Eric Sosman <esosman@ieee-dot-org.invalid> - 2012-02-13 08:14 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Eric Sosman <esosman@ieee-dot-org.invalid> - 2012-02-13 08:17 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-02-13 21:52 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) James Kuyper <jameskuyper@verizon.net> - 2012-02-13 17:08 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Eric Sosman <esosman@ieee-dot-org.invalid> - 2012-02-13 20:44 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-13 13:16 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 11:18 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) "MikeWhy" <boat042-nospam@yahoo.com> - 2012-02-13 15:18 -0600
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) James Kuyper <jameskuyper@verizon.net> - 2012-02-13 16:26 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) "MikeWhy" <boat042-nospam@yahoo.com> - 2012-02-13 16:05 -0600
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) James Kuyper <jameskuyper@verizon.net> - 2012-02-13 17:13 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-13 23:35 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 17:25 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-14 01:45 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 18:55 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Miles Bader <miles@gnu.org> - 2012-02-14 11:51 +0900
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-14 03:13 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 20:39 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Miles Bader <miles@gnu.org> - 2012-02-14 13:25 +0900
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 23:22 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) "MikeWhy" <boat042-nospam@yahoo.com> - 2012-02-14 02:56 -0600
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-14 09:13 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) "MikeWhy" <boat042-nospam@yahoo.com> - 2012-02-14 11:16 -0600
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-14 12:27 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Eric Sosman <esosman@ieee-dot-org.invalid> - 2012-02-13 23:04 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Miles Bader <miles@gnu.org> - 2012-02-14 14:00 +0900
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Robert Wessel <robertwessel2@yahoo.com> - 2012-02-14 00:45 -0600
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-02-14 14:22 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Robert Wessel <robertwessel2@yahoo.com> - 2012-02-14 13:06 -0600
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-14 12:40 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) James Kuyper <jameskuyper@verizon.net> - 2012-02-13 23:05 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Miles Bader <miles@gnu.org> - 2012-02-14 14:01 +0900
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Keith Thompson <kst-u@mib.org> - 2012-02-14 03:01 -0800
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Lowell Gilbert <lgusenet@be-well.ilk.org> - 2012-02-14 12:53 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) James Kuyper <jameskuyper@verizon.net> - 2012-02-14 14:39 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) jgk@panix.com (Joe keane) - 2012-02-14 20:45 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-02-14 22:57 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Keith Thompson <kst-u@mib.org> - 2012-02-14 15:38 -0800
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-02-15 00:22 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Robert Wessel <robertwessel2@yahoo.com> - 2012-02-15 00:39 -0600
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-02-15 08:00 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-13 22:00 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 17:04 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2012-02-13 16:15 -0800
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-14 00:46 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 18:31 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 18:41 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-14 02:33 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 20:20 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-14 03:26 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 20:49 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Robert Wessel <robertwessel2@yahoo.com> - 2012-02-14 00:24 -0600
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-13 23:42 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) James Kuyper <jameskuyper@verizon.net> - 2012-02-14 06:48 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-02-14 13:51 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-14 08:42 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-02-14 19:58 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-02-14 14:27 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) BGB <cr88192@hotmail.com> - 2012-02-14 09:10 -0700
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-02-14 20:02 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Noob <root@127.0.0.1> - 2012-02-13 15:22 +0100
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) legalize+jeeves@mail.xmission.com (Richard) - 2012-02-13 18:49 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) James Kuyper <jameskuyper@verizon.net> - 2012-02-13 13:55 -0500
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Juha Nieminen <nospam@thanks.invalid> - 2012-02-13 19:14 +0000
Re: C/C++ pitfalls related to 64-bits (unsigned long & double) Barry Schwarz <schwarzb@dqel.com> - 2012-02-13 12:14 -0800
Page 3 of 4 — ← Prev page 1 2 [3] 4 Next page →
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2012-02-14 03:01 -0800 |
| Message-ID | <lnd39hisqp.fsf@nuthaus.mib.org> |
| In reply to | #17274 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> BGB <cr88192@hotmail.com> writes:
[...]
>> as I understand it, the entire range of 32 bit integers can be exactly
>> represented by a double.
>
> In the architecture in question, yes.
[...]
In any conforming C implementation; the requirements on double are such
that it can represent any 32-bit integer value exactly.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Lowell Gilbert <lgusenet@be-well.ilk.org> |
|---|---|
| Date | 2012-02-14 12:53 -0500 |
| Message-ID | <44y5s5i9nh.fsf@be-well.ilk.org> |
| In reply to | #17299 |
Keith Thompson <kst-u@mib.org> writes: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >> BGB <cr88192@hotmail.com> writes: > [...] >>> as I understand it, the entire range of 32 bit integers can be exactly >>> represented by a double. >> >> In the architecture in question, yes. > [...] > > In any conforming C implementation; the requirements on double are such > that it can represent any 32-bit integer value exactly. Because of the Usual Arithmetic Conversions, or is there some other reason? -- Lowell Gilbert, embedded/networking software engineer http://be-well.ilk.org/~lowell/
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2012-02-14 14:39 -0500 |
| Message-ID | <4F3AB88E.4020509@verizon.net> |
| In reply to | #17319 |
On 02/14/2012 12:53 PM, Lowell Gilbert wrote: > Keith Thompson <kst-u@mib.org> writes: > >> Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >>> BGB <cr88192@hotmail.com> writes: >> [...] >>>> as I understand it, the entire range of 32 bit integers can be exactly >>>> represented by a double. >>> >>> In the architecture in question, yes. >> [...] >> >> In any conforming C implementation; the requirements on double are such >> that it can represent any 32-bit integer value exactly. > > Because of the Usual Arithmetic Conversions, > or is there some other reason? Those rules tell you what conversions must occur; they don't tell you what the results must be, and in particular they don't tell you anything about which values can be represented exactly. Section 5.2.4.2.2, "Characteristics of floating types" describes a model for a floating point representation. An implementation is not required to use precisely that representation, but it must use one that's sufficiently similar that it's characteristics can be described in terms of that model. In that model, the smallest integer that cannot be represented exactly is pow(b,p+1)+1. Paragraph 11 requires that FLT_RADIX, (corresponding to 'b' in the model) must be an integer with a value of at least 2. Paragraph 13 requires that DBL_EPSILON (corresponding to pow(b,1-p) in the model) must be 1e-9 or smaller, which imposes a minimum value of p for any given b. The description of 'p' implies, but does not explicitly require, that it is an integer. I can't figure out how a non-integral value for 'p' could be implemented. With integer values for both b and p, the smallest value you can get for an unrepresentable integer occurs for b==2 and p==31, for which DBL_EPSILON is 2^-30; the corresponding smallest unrepresentable integer is 2^32+1.
[toc] | [prev] | [next] | [standalone]
| From | jgk@panix.com (Joe keane) |
|---|---|
| Date | 2012-02-14 20:45 +0000 |
| Message-ID | <jheh5p$s7h$1@reader1.panix.com> |
| In reply to | #17251 |
In article <jhc1g6$afj$1@dont-email.me>, MikeWhy <boat042-nospam@yahoo.com> wrote: >Still wondering here about the "up for grabs" part. It seems to imply >some edge condition that isn't accounted for. a) machine has internal format that is superset of 'long' and 'double' b) compiler notice the code does long -> double -> long and say 'screw that, don't do nothing'[1] [1] in general, people don't get mad if you give -more- precision than that required, just supply a 'yes i'm a masochist' option
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2012-02-14 22:57 +0000 |
| Message-ID | <jheosg$qa6$1@speranza.aioe.org> |
| In reply to | #17330 |
In comp.lang.c++ Joe keane <jgk@panix.com> wrote: (snip) > a) machine has internal format that is superset of 'long' and 'double' > b) compiler notice the code does: long -> double -> long > and say 'screw that, don't do nothing'[1] > [1] in general, people don't get mad if you give -more- precision than > that required, just supply a 'yes i'm a masochist' option gcc has the --float-store option, requiring it to store intermediate values and refetch them (hopefully in cache) to avoid the excess precision problem. I don't know if that also applied to compile time expression evaluation, though. There are some algorithms that require a consistent precision, and that will fail if sometimes given more. -- glen
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2012-02-14 15:38 -0800 |
| Message-ID | <ln7gzphtpa.fsf@nuthaus.mib.org> |
| In reply to | #17330 |
jgk@panix.com (Joe keane) writes:
[...]
> [1] in general, people don't get mad if you give -more- precision than
> that required, just supply a 'yes i'm a masochist' option
People will sometimes get quite mad if you give them *inconsistent*
precision.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2012-02-15 00:22 +0000 |
| Message-ID | <jhetra$4b9$2@speranza.aioe.org> |
| In reply to | #17341 |
In comp.lang.c++ Keith Thompson <kst-u@mib.org> wrote: > jgk@panix.com (Joe keane) writes: >> [1] in general, people don't get mad if you give -more- precision than >> that required, just supply a 'yes i'm a masochist' option > People will sometimes get quite mad if you give them *inconsistent* > precision. Well, for the long story, when the 8087 was developed, the idea was for an infinite register stack. When it was full, there would be an interrupt, some would be spilled to memory, and then continue on. The chip was designed and built before anyone tried to write the software to do it, when it was found not to be possible. Why it wasn't fixed for the 80287 and 80837, I don't know. That would, at least, have allowed for intermediate values to always have extra precision. Now, when you add optimizations, such as common subexpression elimination, and keep values in registers between statements, then again you have inconsistent precision. The infinite stack would have allowed for more consistency. As an example of what is possible, without actually seeing a compiler do it, if you: X=A*B+C*D; Y=A*B-C*D; The compiler might keep C*D with extra precision, but not A*B. Now, if A=C and B=D, Y should be zero but it isn't. With an infinite stack, one might hope that the intermediates for A*B and C*D had the same precision, extra or not. -- glen
[toc] | [prev] | [next] | [standalone]
| From | Robert Wessel <robertwessel2@yahoo.com> |
|---|---|
| Date | 2012-02-15 00:39 -0600 |
| Message-ID | <88kmj714tu9itfd9lbtvj4m8upuf8t6uge@4ax.com> |
| In reply to | #17345 |
On Wed, 15 Feb 2012 00:22:03 +0000 (UTC), glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote: >In comp.lang.c++ Keith Thompson <kst-u@mib.org> wrote: >> jgk@panix.com (Joe keane) writes: > >>> [1] in general, people don't get mad if you give -more- precision than >>> that required, just supply a 'yes i'm a masochist' option > >> People will sometimes get quite mad if you give them *inconsistent* >> precision. > >Well, for the long story, when the 8087 was developed, the idea >was for an infinite register stack. When it was full, there >would be an interrupt, some would be spilled to memory, and >then continue on. The chip was designed and built before anyone >tried to write the software to do it, when it was found >not to be possible. > >Why it wasn't fixed for the 80287 and 80837, I don't know. > >That would, at least, have allowed for intermediate values >to always have extra precision. I believe the original plan was to do the spills in hardware, but they didn't have the die space, so they decided to punt to software. But as you said, they never tried doing it until it was too late. The problems center around being able to handle multiple exceptional conditions at once - basically you can't quite figure out the exact state of the 8087 at the point where it generates the stack overflow. Once the interrupt happens, several possible exceptions have gotten merged together. And no, it was never fixed.
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2012-02-15 08:00 +0000 |
| Message-ID | <jhfomd$qgp$1@speranza.aioe.org> |
| In reply to | #17358 |
In comp.lang.c++ Robert Wessel <robertwessel2@yahoo.com> wrote: (snip on 8087 stack overflow detection) > I believe the original plan was to do the spills in hardware, but they > didn't have the die space, so they decided to punt to software. But > as you said, they never tried doing it until it was too late. The > problems center around being able to handle multiple exceptional > conditions at once - basically you can't quite figure out the exact > state of the 8087 at the point where it generates the stack overflow. > Once the interrupt happens, several possible exceptions have gotten > merged together. > And no, it was never fixed. Multiple imprecise interrupts. The IBM 360/91 allows for out of order execution. If a program interrupt occurs, it has to finish all instructions that are in the pipeline, possibly generating more exceptions. Also, the PSW might be nowhere near the actual cause. Probably too long ago for C++, though. I know one was running at least until 1981. This was 'fixed' in S/370, as it is hard to do virtual storage if you don't know where the page fault occurred. -- glen
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-02-13 22:00 +0000 |
| Message-ID | <0.3ea307f9a62a254551d3.20120213220013GMT.87k43q5r82.fsf@bsb.me.uk> |
| In reply to | #17232 |
BGB <cr88192@hotmail.com> writes: <snip> > also, even though double has more bits than, say, an integer, does not > mean it will reliably encode an integer's value (it can do so in > theory, and will most often do so, but whether or not it will actually > always do so is more "up for grabs"). It's not up for grabs in C (and C++ is essentially the same in this regard). If the integer can be represented exactly in the floating point type, it must be. <snip> > float or double to int, will generally truncate the value, yielding > the integer representation as rounded towards 0. That's true of the truncated value can be represented as an int. If not, the behaviour is undefined. For example, in the example that triggered this thread my implementation produces zero as the result. > the result then is a tendency for an int->double->int conversion to > have a small chance to drop the integer value towards 0 (why? I don't > know exactly, but I have observed it before). If the int is "in range" you don't have a conforming C implementation. > one can counteract this by fudging the value with a small epsilon > prior to converting back into an integer. > > say, for example (untested, from memory): > (v>=0)?((int)(v+0.0001)):((int)(v-0.0001)); I can't see how this helps. If v is representable exactly as a double, the round trip has no effect so this code is not needed. Can you give me a use-case? > can't say it will always work, but similar seems to work fairly well > IME (at least on generic x86 based targets). -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@hotmail.com> |
|---|---|
| Date | 2012-02-13 17:04 -0700 |
| Message-ID | <jhc8fr$6sk$1@news.albasani.net> |
| In reply to | #17249 |
On 2/13/2012 3:00 PM, Ben Bacarisse wrote: > BGB<cr88192@hotmail.com> writes: > <snip> >> also, even though double has more bits than, say, an integer, does not >> mean it will reliably encode an integer's value (it can do so in >> theory, and will most often do so, but whether or not it will actually >> always do so is more "up for grabs"). > > It's not up for grabs in C (and C++ is essentially the same in this > regard). If the integer can be represented exactly in the floating > point type, it must be. > theoretically, yes. given a double has 52 bits, and int is 32 bits, and it is possible to convert exactly, it should always be reliable. but, I have seen it not work exactly right, albeit in rare cases (IME, usually on 64-bit Linux systems, generally fairly rare and when using AMD chips IME). I haven't seen the issue on Win64 though that I can remember, nor with 32-bit code, so I don't know. it "might" have something to do with SSE for all I know (since 32-bit code typically uses x87, and 64-bit typically uses SSE), or maybe something to do with GCC, or similar. might require researching, like trying to figure how exactly AMD chips implement the "cvtsi2sd" and "cvtsd2si" instructions or similar... (I am not even particularly sure which side of the conversion would have been introducing a loss of accuracy, or if the cause could be something else "in the middle" somewhere). > <snip> >> float or double to int, will generally truncate the value, yielding >> the integer representation as rounded towards 0. > > That's true of the truncated value can be represented as an int. If > not, the behaviour is undefined. For example, in the example that > triggered this thread my implementation produces zero as the result. > I didn't notice that part of the thread until after I posted. >> the result then is a tendency for an int->double->int conversion to >> have a small chance to drop the integer value towards 0 (why? I don't >> know exactly, but I have observed it before). > > If the int is "in range" you don't have a conforming C implementation. > could be. all I know is I am fairly sure I have seen it happen in the past (unless I remember seeing an issue probably with other causes, like maybe arithmetic was being done somewhere was messing it up or similar). I never really went and did an in depth investigation of the problem, as it was fixed easily enough when I ran into it (and is not too much different than other epsilon-type stuff when working with floating-point types). like, the whole: "if(fabs(a-b)<0.000001)" thing to compare for equality or similar. >> one can counteract this by fudging the value with a small epsilon >> prior to converting back into an integer. >> >> say, for example (untested, from memory): >> (v>=0)?((int)(v+0.0001)):((int)(v-0.0001)); > > I can't see how this helps. If v is representable exactly as a double, > the round trip has no effect so this code is not needed. Can you give me > a use-case? > generally, I had seen it in my 3D engine, where in some cases integers ended up getting converted to doubles and back, and sometimes they would get "bumped" in this way. adding a small adjustment seemed to fix the problem. mostly since then I have been working under the assumption of trying to avoid conversions to/from floating point types when possible (partly also as I had made the past observation that these conversions have also tended to be costly). or such...
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.mclean5@btinternet.com> |
|---|---|
| Date | 2012-02-13 16:15 -0800 |
| Message-ID | <c040af34-610a-42c5-85ff-f58b0165cede@dq9g2000vbb.googlegroups.com> |
| In reply to | #17264 |
On Feb 14, 12:04 am, BGB <cr88...@hotmail.com> wrote: > On 2/13/2012 3:00 PM, Ben Bacarisse wrote: > > BGB<cr88...@hotmail.com> writes: > > >> the result then is a tendency for an int->double->int conversion to > >> have a small chance to drop the integer value towards 0 (why? I don't > >> know exactly, but I have observed it before). > > > If the int is "in range" you don't have a conforming C implementation. > > all I know is I am fairly sure I have seen it happen in the past (unless > I remember seeing an issue probably with other causes, like maybe > arithmetic was being done somewhere was messing it up or similar). > Sounds like a hardware bug. The C compiler can't necessarily work round those. -- C programming material on my website http://www.malcolmmclean.site11.com/www
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-02-14 00:46 +0000 |
| Message-ID | <0.a4dc5cc322c68708dbd6.20120214004648GMT.87ehty44xz.fsf@bsb.me.uk> |
| In reply to | #17264 |
BGB <cr88192@hotmail.com> writes: > On 2/13/2012 3:00 PM, Ben Bacarisse wrote: >> BGB<cr88192@hotmail.com> writes: >> <snip> >>> also, even though double has more bits than, say, an integer, does not >>> mean it will reliably encode an integer's value (it can do so in >>> theory, and will most often do so, but whether or not it will actually >>> always do so is more "up for grabs"). >> >> It's not up for grabs in C (and C++ is essentially the same in this >> regard). If the integer can be represented exactly in the floating >> point type, it must be. >> > > theoretically, yes. > > given a double has 52 bits, and int is 32 bits, and it is possible to > convert exactly, it should always be reliable. > > but, I have seen it not work exactly right, albeit in rare cases (IME, > usually on 64-bit Linux systems, generally fairly rare and when using > AMD chips IME). > > I haven't seen the issue on Win64 though that I can remember, nor with > 32-bit code, so I don't know. > > it "might" have something to do with SSE for all I know (since 32-bit > code typically uses x87, and 64-bit typically uses SSE), or maybe > something to do with GCC, or similar. > > might require researching, like trying to figure how exactly AMD chips > implement the "cvtsi2sd" and "cvtsd2si" instructions or similar... (I > am not even particularly sure which side of the conversion would have > been introducing a loss of accuracy, or if the cause could be > something else "in the middle" somewhere). Since this behaviour is required for C implementations to be conforming, deviation from it is important. Was there perhaps a bug report filed? <snip> >>> one can counteract this by fudging the value with a small epsilon >>> prior to converting back into an integer. >>> >>> say, for example (untested, from memory): >>> (v>=0)?((int)(v+0.0001)):((int)(v-0.0001)); >> >> I can't see how this helps. If v is representable exactly as a double, >> the round trip has no effect so this code is not needed. Can you give me >> a use-case? >> > > generally, I had seen it in my 3D engine, where in some cases integers > ended up getting converted to doubles and back, and sometimes they > would get "bumped" in this way. adding a small adjustment seemed to > fix the problem. Can you add a test to the code to print v when (int)(double)v != v && (v >= 0 ? (int)(v+0.0001) : (int)(v-0.0001)) == v ? That way we might get an example of the problem you are reporting. <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@hotmail.com> |
|---|---|
| Date | 2012-02-13 18:31 -0700 |
| Message-ID | <jhcdk8$4h8$1@news.albasani.net> |
| In reply to | #17270 |
On 2/13/2012 5:46 PM, Ben Bacarisse wrote:
> BGB<cr88192@hotmail.com> writes:
>
>> On 2/13/2012 3:00 PM, Ben Bacarisse wrote:
>>> BGB<cr88192@hotmail.com> writes:
>>> <snip>
>>>> also, even though double has more bits than, say, an integer, does not
>>>> mean it will reliably encode an integer's value (it can do so in
>>>> theory, and will most often do so, but whether or not it will actually
>>>> always do so is more "up for grabs").
>>>
>>> It's not up for grabs in C (and C++ is essentially the same in this
>>> regard). If the integer can be represented exactly in the floating
>>> point type, it must be.
>>>
>>
>> theoretically, yes.
>>
>> given a double has 52 bits, and int is 32 bits, and it is possible to
>> convert exactly, it should always be reliable.
>>
>> but, I have seen it not work exactly right, albeit in rare cases (IME,
>> usually on 64-bit Linux systems, generally fairly rare and when using
>> AMD chips IME).
>>
>> I haven't seen the issue on Win64 though that I can remember, nor with
>> 32-bit code, so I don't know.
>>
>> it "might" have something to do with SSE for all I know (since 32-bit
>> code typically uses x87, and 64-bit typically uses SSE), or maybe
>> something to do with GCC, or similar.
>>
>> might require researching, like trying to figure how exactly AMD chips
>> implement the "cvtsi2sd" and "cvtsd2si" instructions or similar... (I
>> am not even particularly sure which side of the conversion would have
>> been introducing a loss of accuracy, or if the cause could be
>> something else "in the middle" somewhere).
>
> Since this behaviour is required for C implementations to be conforming,
> deviation from it is important. Was there perhaps a bug report filed?
>
not at the time, I merely thought of it as an interesting occurrence and
worked around it.
> <snip>
>>>> one can counteract this by fudging the value with a small epsilon
>>>> prior to converting back into an integer.
>>>>
>>>> say, for example (untested, from memory):
>>>> (v>=0)?((int)(v+0.0001)):((int)(v-0.0001));
>>>
>>> I can't see how this helps. If v is representable exactly as a double,
>>> the round trip has no effect so this code is not needed. Can you give me
>>> a use-case?
>>>
>>
>> generally, I had seen it in my 3D engine, where in some cases integers
>> ended up getting converted to doubles and back, and sometimes they
>> would get "bumped" in this way. adding a small adjustment seemed to
>> fix the problem.
>
> Can you add a test to the code to print v when
>
> (int)(double)v != v&&
> (v>= 0 ? (int)(v+0.0001) : (int)(v-0.0001)) == v
>
> ? That way we might get an example of the problem you are reporting.
>
I would have to find an example of it again...
I remember seeing the problem a few years ago in some code of mine, but
don't have any recent memory of bugs resulting from it (but, then again,
this could also be due to code paranoia...).
just went and tried to recreate it, with mixed results:
a raw conversion does not show any issues (seems to always be reliable);
if I add a value to the double, and subtract the same value, then it
starts acting up.
testing the code below in Fedora 13 x86-64 within VMware (yes, not the
raw HW, but I would otherwise have to reboot).
#include <stdio.h>
int main()
{
double d;
int i, j, k;
for(i=0; i<100000000; i++)
{
j=rand()*rand()*i;
d=j;
d=d+1.0; //(1)
d=d-1.0; //(1)
k=d; //(2)
k=(d>=0?(int)(d+0.0001):(int)(d-0.0001)); //(2)
if(j!=k)
printf("%d %d\n", j, k);
}
}
1: if these lines are commented out, then the printf is never called,
but if uncommented (along with using different constant values), then I
start seeing messages (with it off-by-one, rounded towards 0).
2: if I switch to the second form, which makes the fudging, then the
messages disappear (they still appear with the first form).
so, it would seem to be mostly an issue in this case of whether or not
one does any arithmetic on the values (not sure whether or not this
still counts). CPU is an "AMD Athlon II X4 630".
or, at least, this is what I am seeing here...
here is the inner part of the loop (in ASM):
.L4:
movl $0, %eax
call rand
movl %eax, %ebx
movl $0, %eax
call rand
imull %ebx, %eax
imull -20(%rbp), %eax
movl %eax, -24(%rbp)
cvtsi2sd -24(%rbp), %xmm0
movsd %xmm0, -32(%rbp)
movsd -32(%rbp), %xmm1
movsd .LC0(%rip), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -32(%rbp)
movsd -32(%rbp), %xmm0
movsd .LC0(%rip), %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, -32(%rbp)
movsd -32(%rbp), %xmm0
cvttsd2si %xmm0, %eax
movl %eax, -36(%rbp)
movl -24(%rbp), %eax
cmpl -36(%rbp), %eax
je .L3
movl $.LC1, %eax
movl -36(%rbp), %edx
movl -24(%rbp), %ecx
movl %ecx, %esi
movq %rax, %rdi
movl $0, %eax
call printf
.L3:
...
.LC0:
.long 0
.long 1072693248
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@hotmail.com> |
|---|---|
| Date | 2012-02-13 18:41 -0700 |
| Message-ID | <jhce68$59t$1@news.albasani.net> |
| In reply to | #17271 |
On 2/13/2012 6:31 PM, BGB wrote:
> On 2/13/2012 5:46 PM, Ben Bacarisse wrote:
>> BGB<cr88192@hotmail.com> writes:
>>
>>> On 2/13/2012 3:00 PM, Ben Bacarisse wrote:
>>>> BGB<cr88192@hotmail.com> writes:
>>>> <snip>
>>>>> also, even though double has more bits than, say, an integer, does not
>>>>> mean it will reliably encode an integer's value (it can do so in
>>>>> theory, and will most often do so, but whether or not it will actually
>>>>> always do so is more "up for grabs").
>>>>
>>>> It's not up for grabs in C (and C++ is essentially the same in this
>>>> regard). If the integer can be represented exactly in the floating
>>>> point type, it must be.
>>>>
>>>
>>> theoretically, yes.
>>>
>>> given a double has 52 bits, and int is 32 bits, and it is possible to
>>> convert exactly, it should always be reliable.
>>>
>>> but, I have seen it not work exactly right, albeit in rare cases (IME,
>>> usually on 64-bit Linux systems, generally fairly rare and when using
>>> AMD chips IME).
>>>
>>> I haven't seen the issue on Win64 though that I can remember, nor with
>>> 32-bit code, so I don't know.
>>>
>>> it "might" have something to do with SSE for all I know (since 32-bit
>>> code typically uses x87, and 64-bit typically uses SSE), or maybe
>>> something to do with GCC, or similar.
>>>
>>> might require researching, like trying to figure how exactly AMD chips
>>> implement the "cvtsi2sd" and "cvtsd2si" instructions or similar... (I
>>> am not even particularly sure which side of the conversion would have
>>> been introducing a loss of accuracy, or if the cause could be
>>> something else "in the middle" somewhere).
>>
>> Since this behaviour is required for C implementations to be conforming,
>> deviation from it is important. Was there perhaps a bug report filed?
>>
>
> not at the time, I merely thought of it as an interesting occurrence and
> worked around it.
>
>
>> <snip>
>>>>> one can counteract this by fudging the value with a small epsilon
>>>>> prior to converting back into an integer.
>>>>>
>>>>> say, for example (untested, from memory):
>>>>> (v>=0)?((int)(v+0.0001)):((int)(v-0.0001));
>>>>
>>>> I can't see how this helps. If v is representable exactly as a double,
>>>> the round trip has no effect so this code is not needed. Can you
>>>> give me
>>>> a use-case?
>>>>
>>>
>>> generally, I had seen it in my 3D engine, where in some cases integers
>>> ended up getting converted to doubles and back, and sometimes they
>>> would get "bumped" in this way. adding a small adjustment seemed to
>>> fix the problem.
>>
>> Can you add a test to the code to print v when
>>
>> (int)(double)v != v&&
>> (v>= 0 ? (int)(v+0.0001) : (int)(v-0.0001)) == v
>>
>> ? That way we might get an example of the problem you are reporting.
>>
>
> I would have to find an example of it again...
>
> I remember seeing the problem a few years ago in some code of mine, but
> don't have any recent memory of bugs resulting from it (but, then again,
> this could also be due to code paranoia...).
>
> just went and tried to recreate it, with mixed results:
> a raw conversion does not show any issues (seems to always be reliable);
> if I add a value to the double, and subtract the same value, then it
> starts acting up.
>
> testing the code below in Fedora 13 x86-64 within VMware (yes, not the
> raw HW, but I would otherwise have to reboot).
>
> #include <stdio.h>
>
> int main()
> {
> double d;
> int i, j, k;
>
> for(i=0; i<100000000; i++)
> {
> j=rand()*rand()*i;
> d=j;
> d=d+1.0; //(1)
> d=d-1.0; //(1)
> k=d; //(2)
> k=(d>=0?(int)(d+0.0001):(int)(d-0.0001)); //(2)
> if(j!=k)
> printf("%d %d\n", j, k);
> }
> }
>
> 1: if these lines are commented out, then the printf is never called,
> but if uncommented (along with using different constant values), then I
> start seeing messages (with it off-by-one, rounded towards 0).
>
> 2: if I switch to the second form, which makes the fudging, then the
> messages disappear (they still appear with the first form).
>
> so, it would seem to be mostly an issue in this case of whether or not
> one does any arithmetic on the values (not sure whether or not this
> still counts). CPU is an "AMD Athlon II X4 630".
>
> or, at least, this is what I am seeing here...
>
oh yeah, here is an example of the output (with a slight tweak to show
the value held by the double):
1073741824 1073741823 41CFFFFFFFFFFFFF
1073741824 1073741823 41CFFFFFFFFFFFFF
262144 262143 410FFFFFFFFFFFFF
262144 262143 410FFFFFFFFFFFFF
262144 262143 410FFFFFFFFFFFFF
67108864 67108863 418FFFFFFFFFFFFF
4 3 400FFFFFFFFFFFFF
1073741824 1073741823 41CFFFFFFFFFFFFF
1073741824 1073741823 41CFFFFFFFFFFFFF
1073741824 1073741823 41CFFFFFFFFFFFFF
4194304 4194303 414FFFFFFFFFFFFF
4194304 4194303 414FFFFFFFFFFFFF
16384 16383 40CFFFFFFFFFFFFF
67108864 67108863 418FFFFFFFFFFFFF
16384 16383 40CFFFFFFFFFFFFF
hmm, a lot of the same values seem to repeat...
>
> here is the inner part of the loop (in ASM):
> .L4:
> movl $0, %eax
> call rand
> movl %eax, %ebx
> movl $0, %eax
> call rand
> imull %ebx, %eax
> imull -20(%rbp), %eax
> movl %eax, -24(%rbp)
> cvtsi2sd -24(%rbp), %xmm0
> movsd %xmm0, -32(%rbp)
> movsd -32(%rbp), %xmm1
> movsd .LC0(%rip), %xmm0
> addsd %xmm1, %xmm0
> movsd %xmm0, -32(%rbp)
> movsd -32(%rbp), %xmm0
> movsd .LC0(%rip), %xmm1
> subsd %xmm1, %xmm0
> movsd %xmm0, -32(%rbp)
> movsd -32(%rbp), %xmm0
> cvttsd2si %xmm0, %eax
> movl %eax, -36(%rbp)
> movl -24(%rbp), %eax
> cmpl -36(%rbp), %eax
> je .L3
> movl $.LC1, %eax
> movl -36(%rbp), %edx
> movl -24(%rbp), %ecx
> movl %ecx, %esi
> movq %rax, %rdi
> movl $0, %eax
> call printf
> .L3:
>
> ...
>
> .LC0:
> .long 0
> .long 1072693248
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-02-14 02:33 +0000 |
| Message-ID | <0.7532f15ffa230ced061e.20120214023319GMT.87wr7q2lg0.fsf@bsb.me.uk> |
| In reply to | #17272 |
I've set followup-to: since the code is all C.
BGB <cr88192@hotmail.com> writes:
> On 2/13/2012 6:31 PM, BGB wrote:
<snip>
>> just went and tried to recreate it, with mixed results:
>> a raw conversion does not show any issues (seems to always be reliable);
>> if I add a value to the double, and subtract the same value, then it
>> starts acting up.
Yes, it looks like conversion is not the issue.
>> testing the code below in Fedora 13 x86-64 within VMware (yes, not the
>> raw HW, but I would otherwise have to reboot).
>>
>> #include <stdio.h>
>>
>> int main()
>> {
>> double d;
>> int i, j, k;
>>
>> for(i=0; i<100000000; i++)
>> {
>> j=rand()*rand()*i;
>> d=j;
>> d=d+1.0; //(1)
>> d=d-1.0; //(1)
>> k=d; //(2)
>> k=(d>=0?(int)(d+0.0001):(int)(d-0.0001)); //(2)
>> if(j!=k)
>> printf("%d %d\n", j, k);
>> }
>> }
>>
>> 1: if these lines are commented out, then the printf is never called,
>> but if uncommented (along with using different constant values), then I
>> start seeing messages (with it off-by-one, rounded towards 0).
That suggests that the round-trip conversion is happening as expected.
>> 2: if I switch to the second form, which makes the fudging, then the
>> messages disappear (they still appear with the first form).
And this is no longer a mystery. If the +1.0 and -1.0 is producing a
non-integer result, then, yes, this fudge factor will repair it.
>> so, it would seem to be mostly an issue in this case of whether or not
>> one does any arithmetic on the values (not sure whether or not this
>> still counts). CPU is an "AMD Athlon II X4 630".
I see nothing on my Intel hardware (gcc version 4.6.1).
>> or, at least, this is what I am seeing here...
>>
>
> oh yeah, here is an example of the output (with a slight tweak to show
> the value held by the double):
> 1073741824 1073741823 41CFFFFFFFFFFFFF
> 1073741824 1073741823 41CFFFFFFFFFFFFF
> 262144 262143 410FFFFFFFFFFFFF
> 262144 262143 410FFFFFFFFFFFFF
> 262144 262143 410FFFFFFFFFFFFF
> 67108864 67108863 418FFFFFFFFFFFFF
> 4 3 400FFFFFFFFFFFFF
> 1073741824 1073741823 41CFFFFFFFFFFFFF
> 1073741824 1073741823 41CFFFFFFFFFFFFF
> 1073741824 1073741823 41CFFFFFFFFFFFFF
> 4194304 4194303 414FFFFFFFFFFFFF
> 4194304 4194303 414FFFFFFFFFFFFF
> 16384 16383 40CFFFFFFFFFFFFF
> 67108864 67108863 418FFFFFFFFFFFFF
> 16384 16383 40CFFFFFFFFFFFFF
>
> hmm, a lot of the same values seem to repeat...
They are more interesting in hex. (0x4, 0x4000, 0x40000 and so on).
If the result is reliable with 4 (i.e. if you take the loop out, set
j = 4 and find that j != k) it will be simple to see if it the +1.0 or
-1.0 that leads to the loss of precision.
However, this is not a problem for the C implementation because the
accuracy of floating point arithmetic is implementation defined. It may
be a problem for the chip, in that the specification might be that this
should not happen, but such error are very rare, so it's more likely to
be by design.
You said elsewhere that there might have been arithmetic being done.
Had that come right away, we could have cut the whole discussion!
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@hotmail.com> |
|---|---|
| Date | 2012-02-13 20:20 -0700 |
| Message-ID | <jhck0k$ga9$1@news.albasani.net> |
| In reply to | #17277 |
On 2/13/2012 7:33 PM, Ben Bacarisse wrote:
>
> I've set followup-to: since the code is all C.
>
> BGB<cr88192@hotmail.com> writes:
>
>> On 2/13/2012 6:31 PM, BGB wrote:
> <snip>
>>> just went and tried to recreate it, with mixed results:
>>> a raw conversion does not show any issues (seems to always be reliable);
>>> if I add a value to the double, and subtract the same value, then it
>>> starts acting up.
>
> Yes, it looks like conversion is not the issue.
>
>>> testing the code below in Fedora 13 x86-64 within VMware (yes, not the
>>> raw HW, but I would otherwise have to reboot).
>>>
>>> #include<stdio.h>
>>>
>>> int main()
>>> {
>>> double d;
>>> int i, j, k;
>>>
>>> for(i=0; i<100000000; i++)
>>> {
>>> j=rand()*rand()*i;
>>> d=j;
>>> d=d+1.0; //(1)
>>> d=d-1.0; //(1)
>>> k=d; //(2)
>>> k=(d>=0?(int)(d+0.0001):(int)(d-0.0001)); //(2)
>>> if(j!=k)
>>> printf("%d %d\n", j, k);
>>> }
>>> }
>>>
>>> 1: if these lines are commented out, then the printf is never called,
>>> but if uncommented (along with using different constant values), then I
>>> start seeing messages (with it off-by-one, rounded towards 0).
>
> That suggests that the round-trip conversion is happening as expected.
>
>>> 2: if I switch to the second form, which makes the fudging, then the
>>> messages disappear (they still appear with the first form).
>
> And this is no longer a mystery. If the +1.0 and -1.0 is producing a
> non-integer result, then, yes, this fudge factor will repair it.
>
yep, that was the point...
>>> so, it would seem to be mostly an issue in this case of whether or not
>>> one does any arithmetic on the values (not sure whether or not this
>>> still counts). CPU is an "AMD Athlon II X4 630".
>
> I see nothing on my Intel hardware (gcc version 4.6.1).
>
GCC version: "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"
could be a HW specific issue.
>>> or, at least, this is what I am seeing here...
>>>
>>
>> oh yeah, here is an example of the output (with a slight tweak to show
>> the value held by the double):
>> 1073741824 1073741823 41CFFFFFFFFFFFFF
>> 1073741824 1073741823 41CFFFFFFFFFFFFF
>> 262144 262143 410FFFFFFFFFFFFF
>> 262144 262143 410FFFFFFFFFFFFF
>> 262144 262143 410FFFFFFFFFFFFF
>> 67108864 67108863 418FFFFFFFFFFFFF
>> 4 3 400FFFFFFFFFFFFF
>> 1073741824 1073741823 41CFFFFFFFFFFFFF
>> 1073741824 1073741823 41CFFFFFFFFFFFFF
>> 1073741824 1073741823 41CFFFFFFFFFFFFF
>> 4194304 4194303 414FFFFFFFFFFFFF
>> 4194304 4194303 414FFFFFFFFFFFFF
>> 16384 16383 40CFFFFFFFFFFFFF
>> 67108864 67108863 418FFFFFFFFFFFFF
>> 16384 16383 40CFFFFFFFFFFFFF
>>
>> hmm, a lot of the same values seem to repeat...
>
> They are more interesting in hex. (0x4, 0x4000, 0x40000 and so on).
>
> If the result is reliable with 4 (i.e. if you take the loop out, set
> j = 4 and find that j != k) it will be simple to see if it the +1.0 or
> -1.0 that leads to the loss of precision.
>
> However, this is not a problem for the C implementation because the
> accuracy of floating point arithmetic is implementation defined. It may
> be a problem for the chip, in that the specification might be that this
> should not happen, but such error are very rare, so it's more likely to
> be by design.
>
> You said elsewhere that there might have been arithmetic being done.
> Had that come right away, we could have cut the whole discussion!
>
I had to test to find out whether or not it was due to arithmetic.
I remembered seeing the issue, but didn't entirely remember the cause,
but originally it didn't seem particularly relevant, just something
worth fixing...
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-02-14 03:26 +0000 |
| Message-ID | <0.af318c181d1a002f8717.20120214032624GMT.87fwee2izj.fsf@bsb.me.uk> |
| In reply to | #17280 |
BGB <cr88192@hotmail.com> writes: <snip> >> And this is no longer a mystery. If the +1.0 and -1.0 is producing a >> non-integer result, then, yes, this fudge factor will repair it. >> > > yep, that was the point... Not originally. We've gone from "conversions aren't always exact" (i.e. implementing C would be hard in this machine) "to arithmetic is not as accurate as I'd like" which is not a issue for C implementations. <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@hotmail.com> |
|---|---|
| Date | 2012-02-13 20:49 -0700 |
| Message-ID | <jhcllp$ilj$1@news.albasani.net> |
| In reply to | #17281 |
On 2/13/2012 8:26 PM, Ben Bacarisse wrote: > BGB<cr88192@hotmail.com> writes: > <snip> >>> And this is no longer a mystery. If the +1.0 and -1.0 is producing a >>> non-integer result, then, yes, this fudge factor will repair it. >>> >> >> yep, that was the point... > > Not originally. We've gone from "conversions aren't always exact" > (i.e. implementing C would be hard in this machine) "to arithmetic is > not as accurate as I'd like" which is not a issue for C implementations. > ok then, I failed to note the difference, and probably applied a specific / special-case observation to the more general case than it applied. either way...
[toc] | [prev] | [next] | [standalone]
| From | Robert Wessel <robertwessel2@yahoo.com> |
|---|---|
| Date | 2012-02-14 00:24 -0600 |
| Message-ID | <lesjj7tal8cu07kkq93068f4vl2a5ntr13@4ax.com> |
| In reply to | #17271 |
On Mon, 13 Feb 2012 18:31:48 -0700, BGB <cr88192@hotmail.com> wrote:
>On 2/13/2012 5:46 PM, Ben Bacarisse wrote:
>> BGB<cr88192@hotmail.com> writes:
>>
>>> On 2/13/2012 3:00 PM, Ben Bacarisse wrote:
>>>> BGB<cr88192@hotmail.com> writes:
>>>> <snip>
>>>>> also, even though double has more bits than, say, an integer, does not
>>>>> mean it will reliably encode an integer's value (it can do so in
>>>>> theory, and will most often do so, but whether or not it will actually
>>>>> always do so is more "up for grabs").
>>>>
>>>> It's not up for grabs in C (and C++ is essentially the same in this
>>>> regard). If the integer can be represented exactly in the floating
>>>> point type, it must be.
>>>>
>>>
>>> theoretically, yes.
>>>
>>> given a double has 52 bits, and int is 32 bits, and it is possible to
>>> convert exactly, it should always be reliable.
>>>
>>> but, I have seen it not work exactly right, albeit in rare cases (IME,
>>> usually on 64-bit Linux systems, generally fairly rare and when using
>>> AMD chips IME).
>>>
>>> I haven't seen the issue on Win64 though that I can remember, nor with
>>> 32-bit code, so I don't know.
>>>
>>> it "might" have something to do with SSE for all I know (since 32-bit
>>> code typically uses x87, and 64-bit typically uses SSE), or maybe
>>> something to do with GCC, or similar.
>>>
>>> might require researching, like trying to figure how exactly AMD chips
>>> implement the "cvtsi2sd" and "cvtsd2si" instructions or similar... (I
>>> am not even particularly sure which side of the conversion would have
>>> been introducing a loss of accuracy, or if the cause could be
>>> something else "in the middle" somewhere).
>>
>> Since this behaviour is required for C implementations to be conforming,
>> deviation from it is important. Was there perhaps a bug report filed?
>>
>
>not at the time, I merely thought of it as an interesting occurrence and
>worked around it.
>
>
>> <snip>
>>>>> one can counteract this by fudging the value with a small epsilon
>>>>> prior to converting back into an integer.
>>>>>
>>>>> say, for example (untested, from memory):
>>>>> (v>=0)?((int)(v+0.0001)):((int)(v-0.0001));
>>>>
>>>> I can't see how this helps. If v is representable exactly as a double,
>>>> the round trip has no effect so this code is not needed. Can you give me
>>>> a use-case?
>>>>
>>>
>>> generally, I had seen it in my 3D engine, where in some cases integers
>>> ended up getting converted to doubles and back, and sometimes they
>>> would get "bumped" in this way. adding a small adjustment seemed to
>>> fix the problem.
>>
>> Can you add a test to the code to print v when
>>
>> (int)(double)v != v&&
>> (v>= 0 ? (int)(v+0.0001) : (int)(v-0.0001)) == v
>>
>> ? That way we might get an example of the problem you are reporting.
>>
>
>I would have to find an example of it again...
>
>I remember seeing the problem a few years ago in some code of mine, but
>don't have any recent memory of bugs resulting from it (but, then again,
>this could also be due to code paranoia...).
>
>just went and tried to recreate it, with mixed results:
>a raw conversion does not show any issues (seems to always be reliable);
>if I add a value to the double, and subtract the same value, then it
>starts acting up.
>
>testing the code below in Fedora 13 x86-64 within VMware (yes, not the
>raw HW, but I would otherwise have to reboot).
>
>#include <stdio.h>
>
>int main()
>{
> double d;
> int i, j, k;
>
> for(i=0; i<100000000; i++)
> {
> j=rand()*rand()*i;
> d=j;
> d=d+1.0; //(1)
> d=d-1.0; //(1)
> k=d; //(2)
> k=(d>=0?(int)(d+0.0001):(int)(d-0.0001)); //(2)
> if(j!=k)
> printf("%d %d\n", j, k);
> }
>}
>
>1: if these lines are commented out, then the printf is never called,
>but if uncommented (along with using different constant values), then I
>start seeing messages (with it off-by-one, rounded towards 0).
>
>2: if I switch to the second form, which makes the fudging, then the
>messages disappear (they still appear with the first form).
>
>so, it would seem to be mostly an issue in this case of whether or not
>one does any arithmetic on the values (not sure whether or not this
>still counts). CPU is an "AMD Athlon II X4 630".
>
>or, at least, this is what I am seeing here...
>
>
>here is the inner part of the loop (in ASM):
>.L4:
> movl $0, %eax
> call rand
> movl %eax, %ebx
> movl $0, %eax
> call rand
> imull %ebx, %eax
> imull -20(%rbp), %eax
> movl %eax, -24(%rbp)
> cvtsi2sd -24(%rbp), %xmm0
> movsd %xmm0, -32(%rbp)
> movsd -32(%rbp), %xmm1
> movsd .LC0(%rip), %xmm0
> addsd %xmm1, %xmm0
> movsd %xmm0, -32(%rbp)
> movsd -32(%rbp), %xmm0
> movsd .LC0(%rip), %xmm1
> subsd %xmm1, %xmm0
> movsd %xmm0, -32(%rbp)
> movsd -32(%rbp), %xmm0
> cvttsd2si %xmm0, %eax
> movl %eax, -36(%rbp)
> movl -24(%rbp), %eax
> cmpl -36(%rbp), %eax
> je .L3
> movl $.LC1, %eax
> movl -36(%rbp), %edx
> movl -24(%rbp), %ecx
> movl %ecx, %esi
> movq %rax, %rdi
> movl $0, %eax
> call printf
>.L3:
>
>...
>
>.LC0:
> .long 0
> .long 1072693248
The explanation for this, at least, seems simple. You're overflowing
the dynamic range of a double. 32767*32767*100000000 needs a bit more
than 56 bits to represent exactly. That doesn't fit in a double
(assuming an IEEE double, of course). Nor do the results of that
number plus or minus 1.0. If the ints on your system are 32 bit,
there should be no problem, as the number will be reduced to 32 bits
first, if they're 64 bits, you'll have round off error.
I've not looks through all the combinations, but the compilers could
be setting rounding differently, and even for x87 and SSE2
instructions rounding can be set differently at the same time.
Rounding can be different between the x87 store-as-int (FIST rounds
according to the selected x87 rounding mode), SSE2 convert-to-int
(CVTTSD2S always truncates towards zero) and software convert-to-int
(which can do whatever the implementers fancied). Those different
rounding modes could to a lesser or greater degree be masking the
problem. Another variable is that on some implementations, the x87 FP
calculations are done in 80-bit format, at least some of the time, so
you might see no round off errors at all in those cases.
[toc] | [prev] | [next] | [standalone]
Page 3 of 4 — ← Prev page 1 2 [3] 4 Next page →
Back to top | Article view | comp.lang.c
csiph-web