By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,897 Members | 1,969 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,897 IT Pros & Developers. It's quick & easy.

C++ anamaly

P: n/a
If you run this program, it gives very unexpected results. Can anyone
explain the nature of this anamaly? (also what is the function call
[and library to include linux/windows] to execute 'pause');

#include<iostream>
using namespace std;
//void pause(){ unsigned long i=0; while(i++<10000000); }

int main(){
int counter=0;
for(float i=1;i<100;i+=0.1) // pay attention
{ // pause();
std::cout<<i<<"\n";
}

cout<<endl;
return 0;
}

Jul 23 '05 #1
Share this Question
Share on Google+
23 Replies


P: n/a
puzzlecracker wrote:
If you run this program, it gives very unexpected results. Can anyone
explain the nature of this anamaly? (also what is the function call
[and library to include linux/windows] to execute 'pause');

#include<iostream>
using namespace std;
//void pause(){ unsigned long i=0; while(i++<10000000); }

int main(){
int counter=0;
for(float i=1;i<100;i+=0.1) // pay attention
{ // pause();
std::cout<<i<<"\n";
}

cout<<endl;
return 0;
}

I guess the float gets printed as a double (there is no operator<<
overload for float). Use double instead.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #2

P: n/a

Ioannis Vranos wrote:
puzzlecracker wrote:
If you run this program, it gives very unexpected results. Can anyone explain the nature of this anamaly? (also what is the function call
[and library to include linux/windows] to execute 'pause');

#include<iostream>
using namespace std;
//void pause(){ unsigned long i=0; while(i++<10000000); }

int main(){
int counter=0;
for(float i=1;i<100;i+=0.1) // pay attention
{ // pause();
std::cout<<i<<"\n";
}

cout<<endl;
return 0;
}

I guess the float gets printed as a double (there is no operator<<
overload for float). Use double instead.


--
Ioannis Vranos

http://www23.brinkster.com/noicys


SAME THING - I think it has to do with the way floating point numbers
are represented.

Jul 23 '05 #3

P: n/a
"puzzlecracker" <ir*********@gmail.com> wrote in message
news:11*********************@z14g2000cwz.googlegro ups.com...
If you run this program, it gives very unexpected results. Can anyone
explain the nature of this anamaly? (also what is the function call
[and library to include linux/windows] to execute 'pause');


It works just fine for me on gcc 3.3.3.

Can you describe the anomaly that happens on your system?

James
Jul 23 '05 #4

P: n/a
what is the last number being printed in your case?

James Aguilar wrote:
"puzzlecracker" <ir*********@gmail.com> wrote in message
news:11*********************@z14g2000cwz.googlegro ups.com...
If you run this program, it gives very unexpected results. Can anyone explain the nature of this anamaly? (also what is the function call
[and library to include linux/windows] to execute 'pause');


It works just fine for me on gcc 3.3.3.

Can you describe the anomaly that happens on your system?

James


Jul 23 '05 #5

P: n/a
puzzlecracker wrote:
If you run this program, it gives very unexpected results.
What do you think is unexpected about it ?

Can anyone explain the nature of this anamaly?
Round off error, more than likely.

0.1 is a number that can't be represented exactly.

In binary to 23 digits it is represented as the following approximation:

0.00011001100110011001100

Which is 1 10 millionth (approx) in error or more accurately.
1/10485760

When you multiply that error by 1000 you get an error of:
25/262144

i.e. 1 in 100,000 (approx).
(also what is the function call [and library to include linux/windows] to execute 'pause');


What is pause ? Why do you need it ?
Jul 23 '05 #6

P: n/a

Gianni Mariani wrote:
puzzlecracker wrote:
If you run this program, it gives very unexpected results.
What do you think is unexpected about it ?

Can anyone
explain the nature of this anamaly?


Round off error, more than likely.

0.1 is a number that can't be represented exactly.

In binary to 23 digits it is represented as the following

approximation:
0.00011001100110011001100

Which is 1 10 millionth (approx) in error or more accurately.
1/10485760

When you multiply that error by 1000 you get an error of:
25/262144

i.e. 1 in 100,000 (approx).
(also what is the function call
[and library to include linux/windows] to execute 'pause');


What is pause ? Why do you need it ?


how to correct this problem?

Jul 23 '05 #7

P: n/a
puzzlecracker wrote:
Gianni Mariani wrote: ....

Round off error, more than likely.

....
how to correct this problem?
Change the order of operations to minimize the round-off error
accumulation and/or use higher precision (double) numbers.

You can use exact numbers as well - like a quotient type.

This is one example I whipped up to come up with that bit pattern...
template <typename w_T>
w_T gcd( w_T i_v1, w_T i_v2 )
{
w_T l_vl;
w_T l_vs;
if ( i_v1 > i_v2 )
{
l_vl = i_v1;
l_vs = i_v2;
}
else
{
l_vl = i_v2;
l_vs = i_v1;
}

w_T l_t;
w_T l_t2;

do {

l_t2 = l_vl % l_vs;

l_t = l_vl;
l_vl = l_vs;
l_vs = l_t2;
} while( l_t2 );

return l_vl;
}
struct quotient
{
typedef unsigned long long t_type;

bool m_sign;
t_type m_numerator;
t_type m_denominator;

quotient(
bool i_sign,
t_type i_numerator,
t_type i_denominator
)
: m_sign( i_sign ),
m_numerator( i_numerator ),
m_denominator( i_denominator )
{
Simplify();
}

void Simplify()
{
t_type l_gcd = gcd( m_numerator, m_denominator );

if ( l_gcd != 1 )
{
m_numerator /= l_gcd;
m_denominator /= l_gcd;
}
}

quotient operator-() const
{
return quotient( !m_sign, m_numerator, m_denominator );
}

};

quotient operator+( const quotient & i_lhs, const quotient & i_rhs )
{
quotient::t_type l_demgcd = gcd( i_lhs.m_denominator,
i_rhs.m_denominator );

quotient::t_type l_mul_rhs = i_lhs.m_denominator / l_demgcd;
quotient::t_type l_mul_lhs = i_rhs.m_denominator / l_demgcd;
quotient::t_type l_den = l_mul_lhs * i_lhs.m_denominator;

if ( i_lhs.m_sign == i_rhs.m_sign )
{
return quotient(
i_lhs.m_sign,
i_lhs.m_numerator * l_mul_lhs + i_rhs.m_numerator * l_mul_rhs,
l_den
);
}
else
{
quotient::t_type l_num_lhs = i_lhs.m_numerator * l_mul_lhs;
quotient::t_type l_num_rhs = i_rhs.m_numerator * l_mul_rhs;

if ( l_num_lhs > l_num_rhs )
{
return quotient(
i_lhs.m_sign,
l_num_lhs - l_num_rhs,
l_den
);
}
else
{
return quotient(
i_rhs.m_sign,
l_num_rhs - l_num_lhs,
l_den
);
}
}

}

quotient operator-( const quotient & i_lhs, const quotient & i_rhs )
{
return i_lhs + - i_rhs;
}

quotient operator*( const quotient & i_lhs, const quotient & i_rhs )
{
return quotient(
i_rhs.m_sign != i_rhs.m_sign,
i_lhs.m_numerator * i_rhs.m_numerator,
i_lhs.m_denominator * i_rhs.m_denominator
);
}

quotient operator/( const quotient & i_lhs, const quotient & i_rhs )
{
return quotient(
i_rhs.m_sign != i_rhs.m_sign,
i_lhs.m_numerator * i_rhs.m_denominator,
i_lhs.m_denominator * i_rhs.m_numerator
);
}

template<
typename i_char_type,
class i_traits

basic_ostream<i_char_type, i_traits>& operator << (
basic_ostream<i_char_type, i_traits> & i_ostream,
const quotient & i_value
) {

if ( i_value.m_sign )
{
i_ostream << '-';
}

i_ostream << i_value.m_numerator;

if ( i_value.m_denominator != 1 )
{
i_ostream << '/' << i_value.m_denominator;
}

return i_ostream;
}

//////////////////// example of you to use quotient this //////////////

int main()
{
quotient m_value( false, 1, 10 ); // 1/10th or 0.1

quotient m_bit( false, 1, 2 ); // 1/2 or 0,5 - the first bit.

for ( int i = 23; i --; )
{
quotient m_diff = m_value - m_bit;

if ( m_diff.m_sign )
{
std::cout << '0';
}
else
{
std::cout << '1';
m_value = m_diff;
}

m_bit.m_denominator <<= 1;
}

std::cout << " " << m_value << " " << quotient( false, 1000, 1 ) *
m_value;
}
Jul 23 '05 #8

P: n/a
On 29 Jan 2005 22:58:24 -0800 in comp.lang.c++, "puzzlecracker" <ir*********@gmail.com> wrote,
how to correct this problem?


Don't use floating point types for loop counters.
Use long.

Jul 23 '05 #9

P: n/a
"puzzlecracker" <ir*********@gmail.com> wrote in message
news:11**********************@c13g2000cwb.googlegr oups.com...
what is the last number being printed in your case?


99.999 -- the correct number, or, at least, the behavior I would expect.

As I'm sure you know, there is calculation error in all floating point
numbers -- both float, double, and long double. The extent of the error is
dependent upon the hardware, but I'm sure that your teachers have told you
the danger of comparing fps as equal. How is it different if you do 10000
ops on one?
Jul 23 '05 #10

P: n/a
"puzzlecracker" <ir*********@gmail.com> wrote in message
news:11*********************@z14g2000cwz.googlegro ups.com...
If you run this program, it gives very unexpected results. Can anyone
explain the nature of this anamaly? (also what is the function call
[and library to include linux/windows] to execute 'pause');
You'll need to ask about Linux and Windows features in newsgroups
where they're topical.

#include<iostream>
using namespace std;
//void pause(){ unsigned long i=0; while(i++<10000000); }

int main(){
int counter=0;
for(float i=1;i<100;i+=0.1) // pay attention


Yes, you should pay attention:
http://www.parashift.com/c++-faq-lit...html#faq-29.16
http://docs.sun.com/source/806-3568/ncg_goldberg.html

-Mike
Jul 23 '05 #11

P: n/a
James Aguilar wrote:
99.999 -- the correct number, or, at least, the behavior I would expect.

As I'm sure you know, there is calculation error in all floating point
numbers -- both float, double, and long double. The extent of the error is
dependent upon the hardware, but I'm sure that your teachers have told you
the danger of comparing fps as equal. How is it different if you do 10000
ops on one?

Actually if you use double you will get perfectly rounded numbers while
with float you don't. I tried even with /fp:precise of VC++ 2005 Express
Beta which is very precise and expensive and I still got the same things
with float.

100% operator<< converts it to to double and that's why the added
garbage in the end.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #12

P: n/a
"puzzlecracker" <ir*********@gmail.com> wrote in message
news:11*********************@z14g2000cwz.googlegro ups.com...
If you run this program, it gives very unexpected results.


When a program that uses floating-point arithmetic gives unexpected results,
the most common reason is that your expectations are incorrect.
Jul 23 '05 #13

P: n/a
"Ioannis Vranos" <iv*@remove.this.grad.com> wrote in message
news:1107075925.897582@athnrd02...
James Aguilar wrote:
99.999 -- the correct number, or, at least, the behavior I would expect.

As I'm sure you know, there is calculation error in all floating point
numbers -- both float, double, and long double. The extent of the error
is dependent upon the hardware, but I'm sure that your teachers have told
you the danger of comparing fps as equal. How is it different if you do
10000 ops on one?

Actually if you use double you will get perfectly rounded numbers while
with float you don't. I tried even with /fp:precise of VC++ 2005 Express
Beta which is very precise and expensive and I still got the same things
with float.

100% operator<< converts it to to double and that's why the added garbage
in the end.


Interesting. =D

James
Jul 23 '05 #14

P: n/a
James Aguilar wrote:

[ ... ]
As I'm sure you know, there is calculation error in all floating point numbers -- both float, double, and long double.
Actually, neither you nor anybody else knows that -- some floating
point calculations can be done without errors, though I'm the first to
admit that it's neither common nor to be expected.
The extent of the error is
dependent upon the hardware, but I'm sure that your teachers have told you the danger of comparing fps as equal. How is it different if you do 10000 ops on one?

The extent of the error depends not only on the number and type of
operations, but on the mixture of operation and the values involved.
Just for example, repeatedly adding or subtracting an extremely small
number to/from a much larger one vs. multiplying the smaller one and
the adding/subtracting the result. The first case may have no effect on
the value at all while the latter does.

Likewise, the exact values determine whether they will be rounded -- if
the original example used .125 instead of .1, no rounding would have
occurred, at least on any ordinary computer (because it's doing the
work in binary, and .125 is a power of 2 where .1 is not).

Ultimately, most problems arise because people are accustomed to
decimal while computers work in binary. We're accustomed to the fact
that 1/3 (for example) can't be expressed precisely in a finite number
of places after the decimal point.

There's a general rule here: if you start with a fraction and you want
to express it in a different number base, then one of two things will
apply: either the prime factors of the denominator of the fraction are
also divisors of the target number base, or else the fraction can't be
expressed precisely in a finite number of places in that base.

Since a computer uses binary, the number base has only one prime
factor: 2. As such, any fraction whose denominator isn't a power of 2
MUST be rounded when expressed by the computer.

--
Later,
Jerry.

The universe is a figment of its own imagination.

Jul 23 '05 #15

P: n/a
On Sun, 30 Jan 2005 11:05:26 +0200, Ioannis Vranos
<iv*@remove.this.grad.com> wrote in comp.lang.c++:
James Aguilar wrote:
99.999 -- the correct number, or, at least, the behavior I would expect.

As I'm sure you know, there is calculation error in all floating point
numbers -- both float, double, and long double. The extent of the error is
dependent upon the hardware, but I'm sure that your teachers have told you
the danger of comparing fps as equal. How is it different if you do 10000
ops on one?

Actually if you use double you will get perfectly rounded numbers while
with float you don't.


Really? Guaranteed by the C++ standard?
I tried even with /fp:precise of VC++ 2005 Express
Beta which is very precise and expensive and I still got the same things
with float.
Oh, I see, we're talking about one particular compiler. What's the
relevance of that in this context?
100% operator<< converts it to to double and that's why the added
garbage in the end.


--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Jul 23 '05 #16

P: n/a
Jack Klein wrote:
Oh, I see, we're talking about one particular compiler. What's the
relevance of that in this context?

I checked the standard and the provided operator<< for cout (which is
basic_ostream<char>) include:
basic_ostream<charT,traits>& operator<<(bool n);
basic_ostream<charT,traits>& operator<<(short n);
basic_ostream<charT,traits>& operator<<(unsigned short n);
basic_ostream<charT,traits>& operator<<(int n);
basic_ostream<charT,traits>& operator<<(unsigned int n);
basic_ostream<charT,traits>& operator<<(long n);
basic_ostream<charT,traits>& operator<<(unsigned long n);
basic_ostream<charT,traits>& operator<<(float f);
basic_ostream<charT,traits>& operator<<(double f);
basic_ostream<charT,traits>& operator<<(long double f);

So it is indeed some floating point precision problem, which however
gets fixed:
#include <iostream>
#include <ostream>
int main()
{
using namespace std;

cout.precision(4);

for(float i=1;i<100;i+=0.1)
cout<<i<<endl;
}


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #17

P: n/a

Ioannis Vranos wrote:
....
So it is indeed some floating point precision problem, which however
gets fixed:

#include <iostream>
#include <ostream>

int main()
{
std::cout.precision(4);

for(float i=1;i<100;i+=0.1)
std::cout<<i<<endl;
}


Not fixed. Hidden.

Just count to 1000, or 10000. I can guarantee you there will be
a point where it fails. The reason is simple: 0.1 is not equal
to the rational number 1/10, but a binary approximation. You
only hide the accumulated error, until it's >0.0001.
Regards,
Michiel Salters

Jul 23 '05 #18

P: n/a
msalters wrote:
Not fixed. Hidden.

Just count to 1000, or 10000. I can guarantee you there will be
a point where it fails. The reason is simple: 0.1 is not equal
to the rational number 1/10, but a binary approximation. You
only hide the accumulated error, until it's >0.0001.

OK I can understand that. However why when we use double everything
works ok instead?
#include <iostream>
#include <ostream>
int main()
{
using namespace std;

for(double i=1; i<100; i+=0.1)
cout<<i<<endl;
}
1
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
2
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
3
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
4
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
4.9
5
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
5.9
6
6.1
6.2
6.3
6.4
6.5
6.6
6.7
6.8
6.9
7
7.1
7.2
7.3
7.4
7.5
7.6
7.7
7.8
7.9
8
8.1
8.2
8.3
8.4
8.5
8.6
8.7
8.8
8.9
9
9.1
9.2
9.3
9.4
9.5
9.6
9.7
9.8
9.9
10
10.1
10.2
10.3
10.4
10.5
10.6
10.7
10.8
10.9
11
11.1
11.2
11.3
11.4
11.5
11.6
11.7
11.8
11.9
12
12.1
12.2
12.3
12.4
12.5
12.6
12.7
12.8
12.9
13
13.1
13.2
13.3
13.4
13.5
13.6
13.7
13.8
13.9
14
14.1
14.2
14.3
14.4
14.5
14.6
14.7
14.8
14.9
15
15.1
15.2
15.3
15.4
15.5
15.6
15.7
15.8
15.9
16
16.1
16.2
16.3
16.4
16.5
16.6
16.7
16.8
16.9
17
17.1
17.2
17.3
17.4
17.5
17.6
17.7
17.8
17.9
18
18.1
18.2
18.3
18.4
18.5
18.6
18.7
18.8
18.9
19
19.1
19.2
19.3
19.4
19.5
19.6
19.7
19.8
19.9
20
20.1
20.2
20.3
20.4
20.5
20.6
20.7
20.8
20.9
21
21.1
21.2
21.3
21.4
21.5
21.6
21.7
21.8
21.9
22
22.1
22.2
22.3
22.4
22.5
22.6
22.7
22.8
22.9
23
23.1
23.2
23.3
23.4
23.5
23.6
23.7
23.8
23.9
24
24.1
24.2
24.3
24.4
24.5
24.6
24.7
24.8
24.9
25
25.1
25.2
25.3
25.4
25.5
25.6
25.7
25.8
25.9
26
26.1
26.2
26.3
26.4
26.5
26.6
26.7
26.8
26.9
27
27.1
27.2
27.3
27.4
27.5
27.6
27.7
27.8
27.9
28
28.1
28.2
28.3
28.4
28.5
28.6
28.7
28.8
28.9
29
29.1
29.2
29.3
29.4
29.5
29.6
29.7
29.8
29.9
30
30.1
30.2
30.3
30.4
30.5
30.6
30.7
30.8
30.9
31
31.1
31.2
31.3
31.4
31.5
31.6
31.7
31.8
31.9
32
32.1
32.2
32.3
32.4
32.5
32.6
32.7
32.8
32.9
33
33.1
33.2
33.3
33.4
33.5
33.6
33.7
33.8
33.9
34
34.1
34.2
34.3
34.4
34.5
34.6
34.7
34.8
34.9
35
35.1
35.2
35.3
35.4
35.5
35.6
35.7
35.8
35.9
36
36.1
36.2
36.3
36.4
36.5
36.6
36.7
36.8
36.9
37
37.1
37.2
37.3
37.4
37.5
37.6
37.7
37.8
37.9
38
38.1
38.2
38.3
38.4
38.5
38.6
38.7
38.8
38.9
39
39.1
39.2
39.3
39.4
39.5
39.6
39.7
39.8
39.9
40
40.1
40.2
40.3
40.4
40.5
40.6
40.7
40.8
40.9
41
41.1
41.2
41.3
41.4
41.5
41.6
41.7
41.8
41.9
42
42.1
42.2
42.3
42.4
42.5
42.6
42.7
42.8
42.9
43
43.1
43.2
43.3
43.4
43.5
43.6
43.7
43.8
43.9
44
44.1
44.2
44.3
44.4
44.5
44.6
44.7
44.8
44.9
45
45.1
45.2
45.3
45.4
45.5
45.6
45.7
45.8
45.9
46
46.1
46.2
46.3
46.4
46.5
46.6
46.7
46.8
46.9
47
47.1
47.2
47.3
47.4
47.5
47.6
47.7
47.8
47.9
48
48.1
48.2
48.3
48.4
48.5
48.6
48.7
48.8
48.9
49
49.1
49.2
49.3
49.4
49.5
49.6
49.7
49.8
49.9
50
50.1
50.2
50.3
50.4
50.5
50.6
50.7
50.8
50.9
51
51.1
51.2
51.3
51.4
51.5
51.6
51.7
51.8
51.9
52
52.1
52.2
52.3
52.4
52.5
52.6
52.7
52.8
52.9
53
53.1
53.2
53.3
53.4
53.5
53.6
53.7
53.8
53.9
54
54.1
54.2
54.3
54.4
54.5
54.6
54.7
54.8
54.9
55
55.1
55.2
55.3
55.4
55.5
55.6
55.7
55.8
55.9
56
56.1
56.2
56.3
56.4
56.5
56.6
56.7
56.8
56.9
57
57.1
57.2
57.3
57.4
57.5
57.6
57.7
57.8
57.9
58
58.1
58.2
58.3
58.4
58.5
58.6
58.7
58.8
58.9
59
59.1
59.2
59.3
59.4
59.5
59.6
59.7
59.8
59.9
60
60.1
60.2
60.3
60.4
60.5
60.6
60.7
60.8
60.9
61
61.1
61.2
61.3
61.4
61.5
61.6
61.7
61.8
61.9
62
62.1
62.2
62.3
62.4
62.5
62.6
62.7
62.8
62.9
63
63.1
63.2
63.3
63.4
63.5
63.6
63.7
63.8
63.9
64
64.1
64.2
64.3
64.4
64.5
64.6
64.7
64.8
64.9
65
65.1
65.2
65.3
65.4
65.5
65.6
65.7
65.8
65.9
66
66.1
66.2
66.3
66.4
66.5
66.6
66.7
66.8
66.9
67
67.1
67.2
67.3
67.4
67.5
67.6
67.7
67.8
67.9
68
68.1
68.2
68.3
68.4
68.5
68.6
68.7
68.8
68.9
69
69.1
69.2
69.3
69.4
69.5
69.6
69.7
69.8
69.9
70
70.1
70.2
70.3
70.4
70.5
70.6
70.7
70.8
70.9
71
71.1
71.2
71.3
71.4
71.5
71.6
71.7
71.8
71.9
72
72.1
72.2
72.3
72.4
72.5
72.6
72.7
72.8
72.9
73
73.1
73.2
73.3
73.4
73.5
73.6
73.7
73.8
73.9
74
74.1
74.2
74.3
74.4
74.5
74.6
74.7
74.8
74.9
75
75.1
75.2
75.3
75.4
75.5
75.6
75.7
75.8
75.9
76
76.1
76.2
76.3
76.4
76.5
76.6
76.7
76.8
76.9
77
77.1
77.2
77.3
77.4
77.5
77.6
77.7
77.8
77.9
78
78.1
78.2
78.3
78.4
78.5
78.6
78.7
78.8
78.9
79
79.1
79.2
79.3
79.4
79.5
79.6
79.7
79.8
79.9
80
80.1
80.2
80.3
80.4
80.5
80.6
80.7
80.8
80.9
81
81.1
81.2
81.3
81.4
81.5
81.6
81.7
81.8
81.9
82
82.1
82.2
82.3
82.4
82.5
82.6
82.7
82.8
82.9
83
83.1
83.2
83.3
83.4
83.5
83.6
83.7
83.8
83.9
84
84.1
84.2
84.3
84.4
84.5
84.6
84.7
84.8
84.9
85
85.1
85.2
85.3
85.4
85.5
85.6
85.7
85.8
85.9
86
86.1
86.2
86.3
86.4
86.5
86.6
86.7
86.8
86.9
87
87.1
87.2
87.3
87.4
87.5
87.6
87.7
87.8
87.9
88
88.1
88.2
88.3
88.4
88.5
88.6
88.7
88.8
88.9
89
89.1
89.2
89.3
89.4
89.5
89.6
89.7
89.8
89.9
90
90.1
90.2
90.3
90.4
90.5
90.6
90.7
90.8
90.9
91
91.1
91.2
91.3
91.4
91.5
91.6
91.7
91.8
91.9
92
92.1
92.2
92.3
92.4
92.5
92.6
92.7
92.8
92.9
93
93.1
93.2
93.3
93.4
93.5
93.6
93.7
93.8
93.9
94
94.1
94.2
94.3
94.4
94.5
94.6
94.7
94.8
94.9
95
95.1
95.2
95.3
95.4
95.5
95.6
95.7
95.8
95.9
96
96.1
96.2
96.3
96.4
96.5
96.6
96.7
96.8
96.9
97
97.1
97.2
97.3
97.4
97.5
97.6
97.7
97.8
97.9
98
98.1
98.2
98.3
98.4
98.5
98.6
98.7
98.8
98.9
99
99.1
99.2
99.3
99.4
99.5
99.6
99.7
99.8
99.9
100


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #19

P: n/a
"Ioannis Vranos" <iv*@remove.this.grad.com> wrote in message
news:1107178499.753183@athnrd02...
msalters wrote:
Not fixed. Hidden.

Just count to 1000, or 10000. I can guarantee you there will be
a point where it fails. The reason is simple: 0.1 is not equal
to the rational number 1/10, but a binary approximation. You
only hide the accumulated error, until it's >0.0001.

OK I can understand that. However why when we use double everything
works ok instead?
#include <iostream>
#include <ostream>
int main()
{
using namespace std;

for(double i=1; i<100; i+=0.1)


Increase the value 100 significantly (e.g. to INT_MAX),
and you'll likely (but not necessarily) see a difference.
With only 100 iterations, the error has not accumulated
sufficiently to be apparent with your code.
cout<<i<<endl;


Another way to show the problem (even with a smaller
number of iterations) is to increase the output precision,
e.g.:

cout << fixed << setprecision(15) << '\n';

I.e. the call to operator<< is outputting a rounded
value, not necessarily the exact value of 'i'.

E.g. The following program:

#include <ios>
#include <iomanip>
#include <iostream>

int main()
{

std::cout << std::fixed
<< std::setprecision(15);

for(double i=0; i < 10; i += 0.1)
std::cout << i << '\n';

return 0;
}

.... when built with VC++ and executed on an Intel
Pentium, gives the output of:

0.000000000000000
0.100000000000000
0.200000000000000
0.300000000000000
0.400000000000000
0.500000000000000
0.600000000000000
0.700000000000000
0.800000000000000
0.900000000000000
1.000000000000000
1.100000000000000
1.200000000000000
1.300000000000000
1.400000000000000
1.500000000000000
1.600000000000000
1.700000000000000
1.800000000000001
1.900000000000001
2.000000000000000
2.100000000000001
2.200000000000001
2.300000000000001
2.400000000000001
2.500000000000001
2.600000000000001
2.700000000000001
2.800000000000001
2.900000000000001
3.000000000000001
3.100000000000001
3.200000000000002
3.300000000000002
3.400000000000002
3.500000000000002
3.600000000000002
3.700000000000002
3.800000000000002
3.900000000000002
4.000000000000002
4.100000000000001
4.200000000000001
4.300000000000001
4.400000000000000
4.500000000000000
4.600000000000000
4.699999999999999
4.799999999999999
4.899999999999999
4.999999999999998
5.099999999999998
5.199999999999998
5.299999999999997
5.399999999999997
5.499999999999996
5.599999999999996
5.699999999999996
5.799999999999995
5.899999999999995
5.999999999999995
6.099999999999994
6.199999999999994
6.299999999999994
6.399999999999993
6.499999999999993
6.599999999999993
6.699999999999992
6.799999999999992
6.899999999999992
6.999999999999991
7.099999999999991
7.199999999999990
7.299999999999990
7.399999999999990
7.499999999999989
7.599999999999989
7.699999999999989
7.799999999999988
7.899999999999988
7.999999999999988
8.099999999999987
8.199999999999987
8.299999999999987
8.399999999999986
8.499999999999986
8.599999999999985
8.699999999999985
8.799999999999985
8.899999999999984
8.999999999999984
9.099999999999984
9.199999999999983
9.299999999999983
9.399999999999983
9.499999999999982
9.599999999999982
9.699999999999982
9.799999999999981
9.899999999999981
9.999999999999981

If you increment 'i' by 0.1 enough times, the error
will eventually work its way toward the more significant
digits and show up even with 'cout's default precision.

Again, don't depend upon the result from 'cout' to
tell you the exact value of a floating point object
An implementation could even have more significant
digits than 15. (check your <limits> header for
your implementation limits.)

It's simply not possible to represent every decimal
floating point value in binary. Behavior of output
functions cannot change this fact.
-Mike

Jul 23 '05 #20

P: n/a
On Mon, 31 Jan 2005 15:34:58 +0200, Ioannis Vranos wrote:
OK I can understand that. However why when we use double everything
works ok instead?
for(double i=1; i<100; i+=0.1)
cout<<i<<endl;
1 <snip> 99.9
100


Given the semantics of the above for loop, I don't think printing "100" is
"ok".

- Jay

Jul 23 '05 #21

P: n/a
Mike Wahler wrote:
"Ioannis Vranos" <iv*@remove.this.grad.com> wrote in message
news:1107178499.753183@athnrd02...
msalters wrote:

Not fixed. Hidden.

Just count to 1000, or 10000. I can guarantee you there will be
a point where it fails. The reason is simple: 0.1 is not equal
to the rational number 1/10, but a binary approximation. You
only hide the accumulated error, until it's >0.0001.

OK I can understand that. However why when we use double everything
works ok instead?
#include <iostream>
#include <ostream>
int main()
{
using namespace std;

for(double i=1; i<100; i+=0.1)

Increase the value 100 significantly (e.g. to INT_MAX),
and you'll likely (but not necessarily) see a difference.
With only 100 iterations, the error has not accumulated
sufficiently to be apparent with your code.

cout<<i<<endl;

Another way to show the problem (even with a smaller
number of iterations) is to increase the output precision,
e.g.:

cout << fixed << setprecision(15) << '\n';

I.e. the call to operator<< is outputting a rounded
value, not necessarily the exact value of 'i'.

E.g. The following program:

#include <ios>
#include <iomanip>
#include <iostream>

int main()
{

std::cout << std::fixed
<< std::setprecision(15);

for(double i=0; i < 10; i += 0.1)
std::cout << i << '\n';

return 0;
}

... when built with VC++ and executed on an Intel
Pentium, gives the output of:

0.000000000000000
0.100000000000000
0.200000000000000
0.300000000000000
0.400000000000000
0.500000000000000
0.600000000000000
0.700000000000000
0.800000000000000
0.900000000000000
1.000000000000000
1.100000000000000
1.200000000000000
1.300000000000000
1.400000000000000
1.500000000000000
1.600000000000000
1.700000000000000
1.800000000000001
1.900000000000001
2.000000000000000
2.100000000000001
2.200000000000001
2.300000000000001
2.400000000000001
2.500000000000001
2.600000000000001
2.700000000000001
2.800000000000001
2.900000000000001
3.000000000000001
3.100000000000001
3.200000000000002
3.300000000000002
3.400000000000002
3.500000000000002
3.600000000000002
3.700000000000002
3.800000000000002
3.900000000000002
4.000000000000002
4.100000000000001
4.200000000000001
4.300000000000001
4.400000000000000
4.500000000000000
4.600000000000000
4.699999999999999
4.799999999999999
4.899999999999999
4.999999999999998
5.099999999999998
5.199999999999998
5.299999999999997
5.399999999999997
5.499999999999996
5.599999999999996
5.699999999999996
5.799999999999995
5.899999999999995
5.999999999999995
6.099999999999994
6.199999999999994
6.299999999999994
6.399999999999993
6.499999999999993
6.599999999999993
6.699999999999992
6.799999999999992
6.899999999999992
6.999999999999991
7.099999999999991
7.199999999999990
7.299999999999990
7.399999999999990
7.499999999999989
7.599999999999989
7.699999999999989
7.799999999999988
7.899999999999988
7.999999999999988
8.099999999999987
8.199999999999987
8.299999999999987
8.399999999999986
8.499999999999986
8.599999999999985
8.699999999999985
8.799999999999985
8.899999999999984
8.999999999999984
9.099999999999984
9.199999999999983
9.299999999999983
9.399999999999983
9.499999999999982
9.599999999999982
9.699999999999982
9.799999999999981
9.899999999999981
9.999999999999981

If you increment 'i' by 0.1 enough times, the error
will eventually work its way toward the more significant
digits and show up even with 'cout's default precision.

Again, don't depend upon the result from 'cout' to
tell you the exact value of a floating point object
An implementation could even have more significant
digits than 15. (check your <limits> header for
your implementation limits.)

It's simply not possible to represent every decimal
floating point value in binary. Behavior of output
functions cannot change this fact.

Thanks for the clarification.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #22

P: n/a

"Jay Nabonne" <ja*********@sonicNOSPAM.com> wrote in message
news:pa****************************@sonicNOSPAM.co m...
On Mon, 31 Jan 2005 15:34:58 +0200, Ioannis Vranos wrote:
OK I can understand that. However why when we use double everything
works ok instead?
for(double i=1; i<100; i+=0.1)
cout<<i<<endl;


1

<snip>
99.9
100


Given the semantics of the above for loop, I don't think printing "100" is
"ok".


Why not? What do you feel should have been printed?

-Mike
Jul 23 '05 #23

P: n/a
Jay Nabonne wrote:

On Mon, 31 Jan 2005 15:34:58 +0200, Ioannis Vranos wrote:
OK I can understand that. However why when we use double everything
works ok instead?
for(double i=1; i<100; i+=0.1)
cout<<i<<endl;


1

<snip>
99.9
100


Given the semantics of the above for loop, I don't think printing "100" is
"ok".


The point is:
i does not equal 100. It just gets printed that way, because
the output function *rounds* that number. i has a value that
is slightly less then 100, lets say 99.999999998. Therefore i
is indeed less then 100, thus the loop gets executed one
more time. It is only during output that 99.999999998 gets
*rounded* to print 100

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 23 '05 #24

This discussion thread is closed

Replies have been disabled for this discussion.