Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
How can I check a number for irrationality? We enter an irrational number and use only the standard std library.
All floating-point numbers can be represented in the form x = significand × 2exponent, where significand and exponent are integers. All such numbers are rational by definition. That's why this problem has only an approximate solution.
One possible approach is to expand a number into a continued fraction. If you encounter very small or zero denominator, the input number is approximately rational. Or, better, if all denominators are not small, then the number is approximately irrational.
Rough idea:
bool is_rational(double x) {
x = std::abs(x);
for (int i = 0; i < 20; ++i) {
const auto a = std::floor(x);
if (x - a < 1e-8)
return true;
x = 1 / (x - a);
}
return false;
}
int main() {
std::cout << std::boolalpha;
std::cout << is_rational(2019. / 9102.) << std::endl; // Output: true
std::cout << is_rational(std::sqrt(2)) << std::endl; // Output: false
}
One should think about the optimal choice of magic numbers inside is_rational().
As #Jabberwocky pointed out, you won't be able to verify whether the number is truly irrational with computational means.
Looking at it like a typical student's assignment, my best bet it trying to approach the number by division without creating an endless loop. Consider using Hurwitz's Theorem or Dirichlet's approximation theorem.
Either way you will have to set some boundary for your computation (your precision), after how many digits you consider the number irrational.
Irrational number are... Well.. irational. Meaning you can't represent them with a Numerical Value, that's why we write them via a symbole (eg: π). Most you can do is an approximation. For exemple: In Math.h there is approximation for Pi as long double.
If you want something more accurate you can use a byte array to reimplements something like BigNum but it will still be an approximation.
We enter an irrational number
If your question was about an Input (cin) then just grab it as a string and do an aproximation.
The amount of memory your computer has is finite. The number of rational numbers is infinite. More importantly, the amount of rational number with a decimal expression too long for your computer to store it is infinite as well (and this is the same to every computer in the world). This is due to the fact that you can build a rational number as "long" as you want just by adding random digits to it.
A computer can't really work with (all) real numbers. As far as I know the only thing computers do is work with a limited accuracy (although accurate enough to be very useful) . All of the numbers they work with are rational.
Given a number, the only thing you can ask your computer to do for you is to calculate its decimal expression to some extent after enough time. All numbers your computer is able to do this with are known as the set of computable numbers. But even this set is "small" when compared with the real numbers set in terms of cardinality.
Therefore, a computer has no way to decide wheter if a number is rational or not, as the concept of number they work with is too simple for doing that.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Is there a way to convert a double into an integer without risking any undesired errors in the process? I read in Programming - Principles and Practice Using C++ (a book written by the creator of c++) that doubles cannot be turned into integers, but I've put it to the test, and it converts properly about 80% of the time. What's the best way to do this with no risk at all, if it's even possible?
So for example, this converts properly.
double bruh = 10.0;
int a = bruh;
cout << bruh << "\n";
But this doesn't.
double bruh = 10.9;
int a = bruh;
cout << bruh << "\n";
In short, it doesn't round automatically so I think that's what constitutes it as "unsafe".
It it not possible to convert all doubles to integers with no risk of losing data.
First, if the double contains a fractional part (42.9), that fractional part will be lost.
Second, doubles can hold a much larger range of values than most integers, something around 1.7e308, so when you get into the larger values you simply won't be able to store them into an integer.
way to convert a double into an integer without risking any undesired errors
in short, it doesn't round automatically so I think that's what constitutes it as "unsafe"
To convert to an integer value:
x = round(x);
To convert to an integer type:
Start with a round function like long lround(double x);. It "Returns the integer value that is nearest in value to x, with halfway cases rounded away from zero."
If the round result is outside the long range, problems occur and code may want to test for that first.
// Carefully form a double the is 1 more than LONG_MAX
#define LONG_MAXP1 ((LONG_MAX/2 + 1)*2.0)
long val = 0;
if (x - LONG_MAXP1 < -0.5 && x - LONG_MIN > -0.5) {
val = lround(x);
} else {
Handle_error();
}
Detail: in order to test if a double is in range to round to a long, it is important to test the endpoints carefully. The mathematical valid range is (LONG_MIN-0.5 ... LONG_MAX + 0.5), yet those endpoints may not be exactly representable as a double. Instead code uses nearby LONG_MIN and LONG_MAXP1 whose magnitudes are powers of 2 and easy to represent exactly as a double.
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.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Is it possible to compute arithmetic-geometric mean without using an epsilon in C++?
Here is my code:
double agm(double a, double b)
{
if(a > b)
{
a = a + b;
b = a - b;
a = a - b;
}
double aCurrent(a), bCurrent(b),
aNext(a), bNext(b);
while(aCurrent - bCurrent != 0)
{
aNext = sqrt(aCurrent*bCurrent);
bNext = (aCurrent+bCurrent)*0.5;
aCurrent = aNext;
bCurrent = bNext;
}
return aCurrent;
}
double sqrt(double x)
{
double res(x * 0.5);
do
{
res = (res + x/res) * 0.5;
} while(abs(res*res - x) > 1.0e-9);
return res;
}
And it runs forever.
Actually it is very clear what I was asking. It is just that you never met the problem and maybe lazy to think about it and are saying at once that there is nothing to talk about.
So, here is the solution I was looking for:
Instead of eps we can just add the following condition
if(aCurrent <= aPrev || bPrev <= bCurrent || bCurrent <= aCurrent )
And if the condition is true, then it means that we have computed the arithmetic-geometric mean with the most precision possible on our machine. As you can see there is no eps.
Using an eps in the question and answer means comparing that we say that two double numbers are equal when the difference between them is less than eps.
Please, reconsider opening the question.
Of course you can. It suffices to limit the number of iterations to the maximum required for convergence in any case, which should be close to the logarithm of the number of significant bits in the floating-point representation.
The same reasoning holds for the square root. (With a good starting approximation based on the floating-point exponent, i.e. at most a factor 2 away from the exact root, 5 iterations always suffice for doubles).
As a side note, avoid using absolute tolerances. Floating-point values can vary in a very wide range. They can be so large that the tolerance is 0 in comparison, or so tiny that they are below the tolerance itself. Prefer relative tolerances, with the extra difficulty that there is no relative tolerance to 0.
No, it's not possible without using an epsilon. Floating point arithmetic is an approximation of real arithmetic, and usually generates roundoff errors. As a result, it's unlikely the two calculation sequences used to compute the AGM will ever converge to exactly the same floating point numbers. So rather than test whether two floating point numbers are equal, you need to test whether they're close enough to each other to consider them effectively equal. And that's done by calculating the difference and testing whether it's really small.
You can either use a hard-coded epsilon value, or calculate it relative to the size of the numbers. The latter tends to be better, because it allows you to work with different number scales. E.g. you shouldn't use the same epsilon to try to calculate the square root of 12345 and 0.000012345; 0.01 might be adequate for the large number, but you'd need something like 0.000001 for the small number.
See What every programmer should know about floating point
I am writing a function in c++ that is supposed to find the largest single digit in the number passed (inputValue). For example, the answer for .345 is 5. However, after a while, the program is changing the inputValue to something along the lines of .3449 (and the largest digit is then set to 9). I have no idea why this is happening. Any help to resolve this problem would be greatly appreciated.
This is the function in my .hpp file
void LargeInput(const double inputValue)
//Function to find the largest value of the input
{
int tempMax = 0,//Value that the temporary max number is in loop
digit = 0,//Value of numbers after the decimal place
test = 0,
powerOten = 10;//Number multiplied by so that the next digit can be checked
double number = inputValue;//A variable that can be changed in the function
cout << "The number is still " << number << endl;
for (int k = 1; k <= 6; k++)
{
test = (number*powerOten);
cout << "test: " << test << endl;
digit = test % 10;
cout << (static_cast<int>(number*powerOten)) << endl;
if (tempMax < digit)
tempMax = digit;
powerOten *= 10;
}
return;
}
You cannot represent real numbers (doubles) precisely in a computer - they need to be approximated. If you change your function to work on longs or ints there won't be any inaccuracies. That seems natural enough for the context of your question, you're just looking at the digits and not the number, so .345 can be 345 and get the same result.
Try this:
int get_largest_digit(int n) {
int largest = 0;
while (n > 0) {
int x = n % 10;
if (x > largest) largest = x;
n /= 10;
}
return largest;
}
This is because the fractional component of real numbers is in the form of 1/2^n. As a result you can get values very close to what you want but you can never achieve exact values like 1/3.
It's common to instead use integers and have a conversion (like 1000 = 1) so if you had the number 1333 you would do printf("%d.%d", 1333/1000, 1333 % 1000) to print out 1.333.
By the way the first sentence is a simplification of how floating point numbers are actually represented. For more information check out; http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding
This is how floating point number work, unfortunately. The core of the problem is that there are an infinite number of floating point numbers. More specifically, there are an infinite number of values between 0.1 and 0.2 and there are an infinite number of values between 0.01 and 0.02. Computers, however, have a finite number of bits to represent a floating point number (64 bits for a double precision number). Therefore, most floating point numbers have to be approximated. After any floating point operation, the processor has to round the result to a value it can represent in 64 bits.
Another property of floating point numbers is that as number get bigger they get less and less precise. This is because the same 64 bits have to be able to represent very big numbers (1,000,000,000) and very small numbers (0.000,000,000,001). Therefore, the rounding error gets larger when working with bigger numbers.
The other issue here is that you are converting from floating point to integer. This introduces even more rounding error. It appears that when (0.345 * 10000) is converted to an integer, the result is closer to 3449 than 3450.
I suggest you don't convert your numbers to integers. Write your program in terms of floating point numbers. You can't use the modulus (%) operator on floating point numbers to get a value for digit. Instead use the fmod function in the C math library (cmath.h).
As other answers have indicated, binary floating-point is incapable of representing most decimal numbers exactly. Therefore, you must reconsider your problem statement. Some alternatives are:
The number is passed as a double (specifically, a 64-bit IEEE-754 binary floating-point value), and you wish to find the largest digit in the decimal representation of the exact value passed. In this case, the solution suggested by user millimoose will work (provided the asprintf or snprintf function used is of good quality, so that it does not incur rounding errors that prevent it from producing correctly rounded output).
The number is passed as a double but is intended to represent a number that is exactly representable as a decimal numeral with a known number of digits. In this case, the solution suggested by user millimoose again works, with the format specification altered to convert the double to decimal with the desired number of digits (e.g., instead of “%.64f”, you could use “%.6f”).
The function is changed to pass the number in another way, such as with decimal floating-point, as a scaled integer, or as a string containing a decimal numeral.
Once you have clarified the problem statement, it may be interesting to consider how to solve it with floating-point arithmetic, rather than calling library functions for formatted output. This is likely to have pedagogical value (and incidentally might produce a solution that is computationally more efficient than calling a library function).
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.