Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #17207 > unrolled thread

C/C++ pitfalls related to 64-bits (unsigned long & double)

Started byAlex Vinokur <alex.vinokur@gmail.com>
First post2012-02-13 04:41 -0800
Last post2012-02-13 12:14 -0800
Articles 20 on this page of 73 — 19 participants

Back to article view | Back to comp.lang.c


Contents

  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 →


#17299

FromKeith Thompson <kst-u@mib.org>
Date2012-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]


#17319

FromLowell Gilbert <lgusenet@be-well.ilk.org>
Date2012-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]


#17323

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-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]


#17330

Fromjgk@panix.com (Joe keane)
Date2012-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]


#17340

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2012-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]


#17341

FromKeith Thompson <kst-u@mib.org>
Date2012-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]


#17345

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2012-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]


#17358

FromRobert Wessel <robertwessel2@yahoo.com>
Date2012-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]


#17360

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2012-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]


#17249

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-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]


#17264

FromBGB <cr88192@hotmail.com>
Date2012-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]


#17265

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2012-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]


#17270

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-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]


#17271

FromBGB <cr88192@hotmail.com>
Date2012-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]


#17272

FromBGB <cr88192@hotmail.com>
Date2012-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]


#17277

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-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]


#17280

FromBGB <cr88192@hotmail.com>
Date2012-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]


#17281

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-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]


#17283

FromBGB <cr88192@hotmail.com>
Date2012-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]


#17291

FromRobert Wessel <robertwessel2@yahoo.com>
Date2012-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