Working with floats, adding precision

Pages: 12
Here's my code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
float a=1.23456;

float b=a;
char ch[7]="";
int i;
int count=0;
int precision=1;

do{
  if(b<1){ b*=10; precision--; } //For 0.### numbers
  while(b>10){ b/=10; precision++; }

  //Change to char
  i=b;
  ch[count]=i+'0';
    count++;
    cout<<b<<" - ";  //debug
    b-=i;
    cout<<b<<" - ";  //debug
    b*=10;
    cout<<b<<endl;  //debug
}while(count<6);


My problem is that as B is deducted from, new numbers start adding into the old places. Here is a simple run

lined up for ease
1
2
3
4
5
6
1.23456 - 0.23456    - 2.3456
2.3456  - 0.3456     - 3.456
3.456   - 0.456001   - 4.56001
4.56001 - 0.560013   - 5.60013
5.60013 - 0.600128   - 6.00128
6.00128 - 0.00128174 - 0.0128174


As you see, new numbers start coming into the float, fiving me a problem is a smaller number is used.

So my question is this. either how can I stop numbers besides 0 coming in?
Is there some math formula I can use to chage the new non-zero number to zero?

Thanks.
Last edited on
how can I stop numbers besides 0 coming in?
You can't.

This is a common misconception people have about floating point numbers.
The number 1.23456 is in decimal, but floats are in binary. 1.23456 can't be precisely represented in binary, only approximately. The numbers you see coming from the right are the error between the binary and the decimal representation.
There's a few methods you can use to fix this. From best to worse:
1. Use a better conversion algorithm. I believe the standard method is to actually perform the operation described by the floating point representation, in decimal.
2. Use a double. This may not actually solve it.
3. Multiply by 10^5 and assign to an integer.
Useing doubles worked!

I've not got a problem that is really confusing to me.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
double a=1.23;
double b=a;
char ch[7]="";
int i;
int count=0;
int precision=1;

do{
  if(b<1){ b*=10; precision--; } //For 0.### numbers
  while(b>10){ b/=10; precision++; }

  //Change to char
  cout<<i<<" - "<<b;
  i=b;
  cout<<" - "<<i<<endl;
  ch[count]=i+'0';
  if(b==i)break;

  count++;
  b-=i;
  b*=10;
}while(count<6);


This gives the output

1
2
3
4
5
6
0 - 1.23 - 1
1 - 2.3   - 2
2 - 3      - 2  //<<<<<Problem
2 - 10    - 9
9 - 10    - 9
9 - 10    - 9


Where I pointed out the problem, it should be 2 - 3 - 3, however my statement i=b seems to be disregarded the third time through, therefore not allowing my if statment to stop the loop.

Any clues?
2.23 is represented as exactly 2.23-epsilon. See solutions 1 and 3 above.
Sorry, I may be just missing something here, but I don't see how those will help.

It should be that I is assinged B's value, which is currently 3. But as you see from my run, that I = 2 before, and after my i=b; statement. However, on others, such as line 2, I goes from 1 to 2, as expected when given the value 2.3.

So am I missing something, or was I not clear in my last post? (sorry if it is either)
2.23 is actually being represented as 2.229999... By the third step, b is 2.9999..., which is rounded and printed as 3. If you first <<std::setprecision(20) (#include <iomanip>), you'll see what I mean.
There's really no way around this, other than method #1 I described above, or using sprintf() or std::stringstream.
Well, I guess I'll be going with method one sometime in the future.

Thanks a ton for your help!

Before I mark this thread as solved, can you tell me what file sprintf/snprintf() comes from? Also, is it a C function? (I ask because of the printf part)
<cstdio> and yes.
Strange, I'm not including that in my program.

Okay, too bad there isn't a C++ equivilent.

Thanks again!
Did you not notice my mention of std::stringstream?
Yes. But isn't that for converting strings to streams, not visa versa?
Just like you can send integers, floats, etc. to std::cout using the << operator, you can send the same things to an std::stringstream and get the contents using std::stringstream::str().
There are also rounding algorithms to take a number like 2.999 and round it to the nearest integer value (3). See the following link for some reading and some rounding algorithms:
http://www.cplusplus.com/forum/articles/3638/
Good luck!
Okay, I'll look into that some more then.

Thanks for the article. I actually made myself a simple function that rounds up or down, depending on the number

1
2
3
4
5
float round(float &f){
  if(ceil(f)-f <= f+floor(f)-ceil(f)) return ceil(f);
  else if(ceil(f)-f > f+floor(f)-ceil(f)) return floor(f);
  return -1;
}

I also overloaded it for doubles. What do you think?
That's supposed to be better than:
1
2
3
4
5
6
7
8
  //--------------------------------------------------------------------------
  // Common rounding: round half up
  // Bias: +Infinity
  template <typename FloatType>
  FloatType roundhalfup( const FloatType& value )
    {
    return std::floor( value +0.5 );
    }
?
The functions are different. roundhalfup simply adds 0.5 to your value.

Mine, determins wheter the number is .5+ and if so rounds up, and if it's not then it rounds down.

Looking at it, I've changed it to.

1
2
3
4
5
int round(float f){
  if(ceil(f)-f <= f+floor(f)-ceil(f)) return ceil(f);
  else return floor(f);
  return -1;
}


A little simpler.

See the difference?
Can you provide an example where the two functions will return different values given the same input?
Given the same input, they will return the same.

But here is an example.

1.5 = 2
1.4 = 1
1.5254 = 2
1.4999 = 1

As you see from the last example, it does't work precisely, as the last one should round up to 2.
Still, as long as it's .5+ it rounds up, if not it rounds down.

Working to get it to round correctly. Any ideas?
You don't have any clue what you are talking about, do you?
I'm going away.
Well, I thought I did. But if I don't, please help me to understand. Unless you just don't want to help, then there is no need for you to respond to this post.
Pages: 12