visual studio 2010 showing weird behavior on float/double increment [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Dealing with accuracy problems in floating-point numbers
I am writing an OpenGl animation and am using a float variable "time" to keep track of the time.
I am incrementing the "time" variable by 0.01 .I have certain conditions to fulfil whenever "time" reaches an integer value.The issue is that after a certain time the float increment shows weird behavior.
I start from time = 0 and I see that after "time" reaches 0.83 the next value is 0.839999.
I though this could be related to float precision so I tried using double/long double and I found that instead of reaching the value 1.00 the code is reaching the value 1.0000007.
I tried incrementing by "0.01f" instead of "0.01" but got no success.
Is this some bug in Visual Studio or am I doing it the wrong way?
I could post the code but I don't think it's of much use as I am assigning to "time" just at one place and it's just being used at other places.

Don't ever compare floating point values for equality unless you know exactly what you are doing. I would strongly suggest you use integers (perhaps integer numbers of milliseconds) for this purpose.
See What Every Computer Scientist Should Know About Floating-Point Arithmetic for more information.
Floating point is a fixed-precision format. This is an inherent limitation of fixed-precision formats.
For example, say you used six decimal digits of precision. One-third would be .333333. But if you add one-third three times, you get .999999, not 1. That's the nature of the beast.

Not exactly recommending this, but the issue is that the 0.1 cannot be represented exactly as double. 1.0 can be. So if you make your time-step a (negative) power of two, you will find a difference. By way of illustration:
double delta = 1.0 / 8;
int stopper = 10;
int nextInt = 1;
for (double t = 0; t <= stopper; t += delta)
{
if (t == nextInt)
{
std::cout << "int ";
++nextInt;
}
else
std::cout << " ";
std::cout << t << std::endl;
}

Just round "time" after each increment to make sure it maintains a sensible value.
Something like that:
double round(double value, double precision)
{
return floor(value / precision + 0.5) * precision;
}
time = round(time + 0.1, 0.1);

Related

problem in using 'double' data type in for loops with fractional incrementation [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 3 years ago.
I had a program which requires one to search values from -100.00 to +100.00 with incrementation of 0.01 inside a for loop. But the if conditions arent working properly even if code is correct...
As an example I tried printing a small section i.e if(i==1.5){cout<<"yes...";}
it was not working even though the code was attaining the value i=1.5, i verified that by printing each of the values too.
#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
double i;
for(i=-1.00; i<1.00; i=i+0.01)
{
if(i>-0.04 && i<0.04)
{
cout<<i;
if(i==0.01)
cout<<"->yes ";
else
cout<<"->no ";
}
}
return 0;
}
Output:
-0.04->no -0.03->no -0.02->no -0.02->no -0.01->no 7.5287e-016->no 0.01->no 0.02->no 0.03->no
Process returned 0 (0x0) execution time : 1.391
(notice that 0.01 is being attained but still it prints 'no')
(also notice that 0.04 is being printed even if it wasn't instructed to do so)
use this if(abs(i - 0.01) < 0.00000000001) instead.
double - double precision floating point type. Usually IEEE-754 64 bit
floating point type
The crux of the problem is that numbers are represented in this format as a whole number times a power of two; rational numbers (such as 0.01, which is 1/100) whose denominator is not a power of two cannot be exactly represented.
In simple word, if the number can't be represented by a sum of 1/(2^n) you don't have the exact number you want to use. So to compare two double numbers calculate the absolute difference between them and use a tolerance value e.g. 0.00000000001 .
Doubles are stored in binary format. To cut things short fractional part is written as binary. Now let's imagine it's size is 1 bit. So you've two possible values (for fraction only): .0 and .5. With two bits you have: .0 .25 .5 .75. With three bits: .125 .25 .375 .5 .625 .75 .875. And so on. But you'll never get 0.1. So what computer does? It cheats. It lies to you, that 0.1 you see is 0.1. While it more looks like 0.1000000000000000002 or something like this. Why it looks like 0.1? Because formatting of floating point values has long standing tradition of rounding numbers, so 0.10000000000001 becomes 0.1. As a result 0.1 * 10 won't equal 1.0.
Correct solution is to avoid floating point numbers, unless you don't care for precision. If your program breaks, once your floating point value "changes" by miniscule amount, then you need to find another way. In your case using non-fractional values will be enough:
for(auto ii=-100; ii<100; ++ii)
{
if(ii>-4 && ii<4)
{
cout << (ii / 100.0);
if(ii==1)
cout<<"->yes ";
else
cout<<"->no ";
}
}

Errors in Casting Doubles to Integers [duplicate]

This question already has answers here:
Round a float to a regular grid of predefined points
(11 answers)
Closed 4 years ago.
I am calculating the number of significant numbers past the decimal point. My program discards any numbers that are spaced more than 7 orders of magnitude apart after the decimal point. Expecting some error with doubles, I accounted for very small numbers popping up when subtracting ints from doubles, even when it looked like it should equal zero (To my knowledge this is due to how computers store and compute their numbers). My confusion is why my program does not handle this unexpected number given this random test value.
Having put many cout statements it would seem that it messes up when it tries to cast the final 2. Whenever it casts it casts to 1 instead.
bool flag = true;
long double test = 2029.00012;
int count = 0;
while(flag)
{
test = test - static_cast<int>(test);
if(test <= 0.00001)
{
flag = false;
}
test *= 10;
count++;
}
The solution I found was to cast only once at the beginning, as rounding may produce a negative and terminate prematurely, and to round thenceforth. The interesting thing is that both trunc and floor also had this issue, seemingly turning what should be a 2 into a 1.
My Professor and I were both quite stumped as I fully expected small numbers to appear (most were in the 10^-10 range), but was not expecting that casting, truncing, and flooring would all also fail.
It is important to understand that not all rational numbers are representable in finite precision. Also, it is important to understand that set of numbers which are representable in finite precision in decimal base, is different from the set of numbers that are representable in finite precision in binary base. Finally, it is important to understand that your CPU probably represents floating point numbers in binary.
2029.00012 in particular happens to be a number that is not representable in a double precision IEEE 754 floating point (and it indeed is a double precision literal; you may have intended to use long double instead). It so happens that the closest number that is representable is 2029.000119999999924402800388634204864501953125. So, you're counting the significant digits of that number, not the digits of the literal that you used.
If the intention of 0.00001 was to stop counting digits when the number is close to a whole number, it is not sufficient to check whether the value is less than the threshold, but also whether it is greater than 1 - threshold, as the representation error can go either way:
if(test <= 0.00001 || test >= 1 - 0.00001)
After all, you can multiple 0.99999999999999999999999999 with 10 many times until the result becomes close to zero, even though that number is very close to a whole number.
As multiple people have already commented, that won't work because of limitations of floating-point numbers. You had a somewhat correct intuition when you said that you expected "some error" with doubles, but that is ultimately not enough. Running your specific program on my machine, the closest representable double to 2029.00012 is 2029.0001199999999244 (this is actually a truncated value, but it shows the series of 9's well enough). For that reason, when you multiply by 10, you keep finding new significant digits.
Ultimately, the issue is that you are manipulating a base-2 real number like it's a base-10 number. This is actually quite difficult. The most notorious use cases for this are printing and parsing floating-point numbers, and a lot of sweat and blood went into that. For example, it wasn't that long ago that you could trick the official Java implementation into looping endlessly trying to convert a String to a double.
Your best shot might be to just reuse all that hard work. Print to 7 digits of precision, and subtract the number of trailing zeroes from the result:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
int main() {
long double d = 2029.00012;
auto double_string = (std::stringstream() << std::fixed << std::setprecision(7) << d).str();
auto first_decimal_index = double_string.find('.') + 1;
auto last_nonzero_index = double_string.find_last_not_of('0');
if (last_nonzero_index == std::string::npos) {
std::cout << "7 significant digits\n";
} else if (last_nonzero_index < first_decimal_index) {
std::cout << -(first_decimal_index - last_nonzero_index + 1) << " significant digits\n";
} else {
std::cout << (last_nonzero_index - first_decimal_index) << " significant digits\n";
}
}
It feels unsatisfactory, but:
it correctly prints 5;
the "satisfactory" alternative is possibly significantly harder to implement.
It seems to me that your second-best alternative is to read on floating-point printing algorithms and implement just enough of it to get the length of the value that you're going to print, and that's not exactly an introductory-level task. If you decide to go this route, the current state of the art is the Grisu2 algorithm. Grisu2 has the notable benefit that it will always print the shortest base-10 string that will produce the given floating-point value, which is what you seem to be after.
If you want sane results, you can't just truncate the digits, because sometimes the floating point number will be a hair less than the rounded number. If you want to fix this via a fluke, change your initialization to be
long double test = 2029.00012L;
If you want to fix it for real,
bool flag = true;
long double test = 2029.00012;
int count = 0;
while (flag)
{
test = test - static_cast<int>(test + 0.000005);
if (test <= 0.00001)
{
flag = false;
}
test *= 10;
count++;
}
My apologies for butchering your haphazard indent; I can't abide by them. According to one of my CS professors, "ideally, a computer scientist never has to worry about the underlying hardware." I'd guess your CS professor might have similar thoughts.

Arithmetic to get correct decimal number instead of exponential number in c++ [duplicate]

This question already has answers here:
How To Represent 0.1 In Floating Point Arithmetic And Decimal
(2 answers)
Closed 8 years ago.
int digit = 1;
float result=0.0;
double temp = 200000;
float tick = 0.00100000005;
result = digit/1000000.0;
long long phase = temp*result*1000/tick*1000
result will be equal to 9.99999997e-07. If manually calculate it should be 0.000001
How can I make the exponential num to be 0.000001?
Thanks.
if result = 9.99999997e-07 phase calculated will be 199999,however if result = 0.000001 phase calculated will be 200000.
So my problem is result.
Add in
For finance and certain other uses, the easiest way is to work in multiples of your smallest unit... in your example, it might be "microns":
inline long long units_to_microns(long long units) { return units * 1000000; }
long long digit = units_to_microns(1);
long long result = digit / 1000000;
Then write some custom code to print numbers a decimal point where you want it:
std::string microns_to_string(long long microns)
{
std::ostringstream oss;
oss << microns / 1000000;
if (microns % 1000000)
oss << '.' << std::setfill('0') << std::setw(6) << microns;
return oss.str();
}
A more structured (and reliable) way to do this is offered by the boost Units library. That way, you can specify the units of specific variables, and if e.g. one was in metres and another kilometres, you could add them without any special care.
If you're dealing with irrational numbers and rounding them off to a specific precision early on is not useful, then you're best off either using double (for some more significant digits of precision), or a custom library like GMP - the GNU Multiple Precision Arithmetic Library.
BTW - What Every Computer Scientist Should Know About Floating-Point Arithmetic is commonly recommended reading in this space.
You can't, because the number 1/1000000.0 cannot be represented exactly in binary. You can improve the accuracy by using a double. This type of question is pretty common here. I've found this link to be helpful:
https://docs.python.org/2/tutorial/floatingpoint.html
(it's for Python, but the issues are the same).

C++ decimal checking if statement errors?

I'm doing some homework for a C++ class, and i'm pretty new to C++. I've run into some issues with my if statement... What i'm doing, is i have the user input a time, between 0.00 and 23.59. the : is replaced by a period btw. that part works. i then am seperating the hour and the minute, and checking them to make sure that they are in valid restraints. checking the hour works, but not the minute... heres my code:
minute= startTime - static_cast<int>(startTime);
hour= static_cast<int>(startTime);
//check validity
if (minute > 0.59) {
cout << "ERROR! ENTERED INVALID TIME! SHUTTING DOWN..." << endl;;
return(0);
}
if (hour > 23) {
cout << "ERROR! ENTERED INVALID TIME! SHUTTING DOWN..." << endl;;
return(0);
}
again, the hour works if i enter 23, but if i enter 23.59, i get the error, but if i enter 23.01 i do not. also, if i enter 0.59 it also gives the error, but not 0.58. I tried switching the if(minute > 0.59) to if(minute > 0.6) but for some reason that caused problems elsewhere. i am at a complete loss as to what to do, so any help would be great! thanks a million!
EDIT: i just entered 0.58, and it didnt give me the error... but if i make it a 1.59 it gives an error again... also, upvotes would be nice :D
Floating-point arithmetic (float and double) is inherently fuzzy. There are always some digits behind the decimal point that you don't see in the rounded representation that is sent to your stream, and comparisons can also be fuzzy because the representation you are used to (decimal) is not the one the computer uses (binary).
Represent a time as int hours and int minutes, and your problems will fade away. Most libraries measure time in ticks (usually seconds or microseconds) and do not offer sub-tick resolution. You do well to emulate them.
Comparison of floating point numbers is prone to failure, because very few of them can be represented exactly in base 2. There's always going to be some possibility that two different numbers are going to round in different directions.
The simplest fix is to add a very tiny fudge factor to the number you're comparing:
if (minute > 0.59 + epsilon)
See What Every Computer Scientist Should Know About Floating-Point Arithmetic.
Don't, ever, use double (nor float) to store two integer values using the integer and decimal part as separator. The decimal data types are not precise enough, so you may have wrong results (in case of a round).
A good solution in your case is either to use a struct (or a pair) or even an integer.
With integer, you can use mod or div of multiples of then to extract the real value. Example:
int startTime = 2359;
int hour = startTime / 100;
int minute = startTime % 100;
Although, with struct the code would look simpler and easier to understand (and to maintain).
There's no way you can compare to exactly 0.59; this value
cannot be represented in the machine. You're comparing
something which is very close to 0.59 with something else that
is very close to 0.59.
Personally, I wouldn't input time this way at all. A much
better solution would be to learn how to use std::istream to
read the value. But if you insist, and you have startTime as
your double, you need to multiply it by 100.0 (so that all
of the values that interest you are integers, and can be
represented exactly), then round it, then convert it to an
integer, and use the modulo and division operators on the
integer to extract your values. Something along the lines of:
assert( startTime >= 0.0 && startTime <= 24.0 );
int tmpTime = 100.0 * startTime + 0.5;
int minute = tmpTime % 100;
int hour = tmpTime / 100;
When dealing with integral values, it's much simpler to use
integral types.

Why do simple doubles like 1.82 end up being 1.819999999645634565360? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why does Visual Studio 2008 tell me .9 - .8999999999999995 = 0.00000000000000055511151231257827?
c++
Hey so i'm making a function to return the number of a digits in a number data type given, but i'm having some trouble with doubles.
I figure out how many digits are in it by multiplying it by like 10 billion and then taking away digits 1 by 1 until the double ends up being 0. however when putting in a double of value say .7904 i never exit the function as it keeps taking away digits which never end up being 0 as the resut of .7904 ends up being 7,903,999,988 and not 7,904,000,000.
How can i solve this problem?? Thanks =) ! oh and any other feed back on my code is WELCOME!
here's the code of my function:
/////////////////////// Numb_Digits() ////////////////////////////////////////////////////
enum{DECIMALS = 10, WHOLE_NUMBS = 20, ALL = 30};
template<typename T>
unsigned long int Numb_Digits(T numb, int scope)
{
unsigned long int length= 0;
switch(scope){
case DECIMALS: numb-= (int)numb; numb*=10000000000; // 10 bil (10 zeros)
for(; numb != 0; length++)
numb-=((int)(numb/pow((double)10, (double)(9-length))))* pow((double)10, (double)(9-length)); break;
case WHOLE_NUMBS: numb= (int)numb; numb*=10000000000;
for(; numb != 0; length++)
numb-=((int)(numb/pow((double)10, (double)(9-length))))* pow((double)10, (double)(9-length)); break;
case ALL: numb = numb; numb*=10000000000;
for(; numb != 0; length++)
numb-=((int)(numb/pow((double)10, (double)(9-length))))* pow((double)10, (double)(9-length)); break;
default: break;}
return length;
};
int main()
{
double test = 345.6457;
cout << Numb_Digits(test, ALL) << endl;
cout << Numb_Digits(test, DECIMALS) << endl;
cout << Numb_Digits(test, WHOLE_NUMBS) << endl;
return 0;
}
It's because of their binary representation, which is discussed in depth here:
http://en.wikipedia.org/wiki/IEEE_754-2008
Basically, when a number can't be represented as is, an approximation is used instead.
To compare floats for equality, check if their difference is lesser than an arbitrary precision.
The easy summary about floating point arithmetic :
http://floating-point-gui.de/
Read this and you'll see the light.
If you're more on the math side, Goldberg paper is always nice :
http://cr.yp.to/2005-590/goldberg.pdf
Long story short : real numbers are stored with a fixed, irregular precision, leading to non obvious behaviors. This is unrelated to the language but more a design choice of how to handle real numbers as a whole.
This is because C++ (like most other languages) can not store floating point numbers with infinte precision.
Floating points are stored like this:
sign * coefficient * 10^exponent if you're using base 10.
The problem is that both the coefficient and exponent are stored as finite integers.
This is a common problem with storing floating point in computer programs, you usually get a tiny rounding error.
The most common way of dealing with this is:
Store the number as a fraction (x/y)
Use a delta that allows small deviations (if abs(x-y) < delta)
Use a third party library such as GMP that can store floating point with perfect precision.
Regarding your question about counting decimals.
There is no way of dealing with this if you get a double as input. You cannot be sure that the user actually sent 1.819999999645634565360 and not 1.82.
Either you have to change your input or change the way your function works.
More info on floating point can be found here: http://en.wikipedia.org/wiki/Floating_point
This is because of the way the IEEE floating point standard is implemented, which will vary depending on operations. It is an approximation of precision. Never use logic of if(float == float), ever!
Float numbers are represented in the form Significant digits × baseexponent(IEEE 754). In your case, float 1.82 = 1 + 0.5 + 0.25 + 0.0625 + ...
Since only a limited digits could be stored, therefore there will be a round error if the float number cannot be represented as a terminating expansion in the relevant base (base 2 in the case).
You should always check relative differences with floating point numbers, not absolute values.
You need to read this, too.
Computers don't store floating point numbers exactly. To accomplish what you are doing, you could store the original input as a string, and count the number of characters.