C++ decimal arithmetic libraries - c++

I'm fairly new to adding additional libraries to Visual Studio (2013) as well as the idea that floats and doubles are usually not accurate enough when dealing with certain things like money. I originally thought that BOOST::Multiprecision cpp_dec_float would solve this problem but as I tested it I noticed some unusually things and realized that I could be wrong. for example,
cpp_dec_float_50 decimal = 0.45;
double dbl = 0.45; //for comparison
cout << fixed << setprecision(50) << "boost: " << decimal << endl;
cout << "double: " << dbl << endl;
would give results like this
boost: 0.45000000000000001110223024625156540423631668090820
double: 0.45000000000000001000000000000000000000000000000000
instead of what I expected (0.45000000000000000000000000000000000000000000000000).
is this not going to be much more accurate than just using floats or doubles? If not, I'm assuming the boost library I just linked to my VS2013 has an arbitrary integer type, would this be acceptable? the only thing I don't like about using integers for such a thing is that I'd probably have to convert interest rates into integers before multiplying it with currency which would likely result in a very, very large number which may or may not cause performance issues.
(assuming BOOST isn't what I need) what are your thoughts on Intel's Decimal Floating-Point Library? I couldn't get it to work (yet) so I'm wondering if it is worth the effort. Are there any other similar libraries worth checking out?

So, you're assigning a number (that is already in floating point) to your decimal variable. So the error that you are concerned about has already been introduced.
Instead, let's assign it with a string containing the correct number:
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
using namespace std;
using boost::multiprecision::cpp_dec_float_50;
int main() {
cpp_dec_float_50 decimal("0.45");
double dbl = 0.45; //for comparison
cout << fixed << setprecision(50) << "boost: " << decimal << endl;
cout << "double: " << dbl << endl;
}
Which outputs:
boost: 0.45000000000000000000000000000000000000000000000000
double: 0.45000000000000001110223024625156540423631668090820

Use Python:
import decimal
d = decimal.Decimal("0.45")
print(d)
outputs 0.45.

Related

c++ print number in hexadecimal right after floor function

I've noticed some weird behaviour in c++ which i don't understand,
i'm trying to print a truncated double in a hexadecimal representation
this code output is 17 which is a decimal representation
double a = 17.123;
cout << hex << floor(a) << '\n';
while this code output is 11 and also my desirable output
double a = 17.123;
long long aASll = floor(a);
cout << hex << aASll << '\n';
as double can get really big numbers i'm afraid of wrong output while storing the truncated number in long long variable, any suggestions or improvements?
Quoting CPPreference's documentation page for std::hex (and friends)
Modifies the default numeric base for integer I/O.
This suggests that std::hex does not have any effect on floating point inputs. The best you are going to get is
cout << hex << static_cast<long long>(floor(a)) << '\n';
or a function that does the same.
uintmax_t from <cstdint> may be useful to get the largest available integer if the values are always positive. After all, what is a negative hex number?
Since a double value can easily exceed the maximum resolution of available integers, this won't cover the whole range. If the floored values exceed what can fit in an integer type, you are going to have to do the conversion by hand or use a big integer library.
Side note: std::hexfloat does something very different and does not work correctly in all compilers due to some poor wording in the current Standard that is has since been hammered out and should be corrected in the next revision.
Just write your own version of floor and have it return an integral value. For example:
long long floorAsLongLong(double d)
{
return (long long)floor(d);
}
int main() {
double a = 17.123;
cout << hex << floorAsLongLong(a) << endl;
}

int array with int variable multiplication gives wrong result c++

I'm learning c++ of my own, and I thought: "Where can I find some problems to solve?"... well, reading in stackoverflow I get interested in euler project, and here I am.
I'm doing the 4th problem (not asking for help BTW), but I have a very strange issue...
In this code, I want to separate a number in "digits"... that way I can say: if the first digit of the number is equal to the last, it is a palindrome number (number that can be read left to right or right to left an will be the same number... example: 90009).
All good, but the problem is when I try to divide an array element into a power...
for example:
90009/power(10,4)=9 right? (using integers of course)...
Well, code assigns the 9 to arregloDeNumero[4], and then
arregloDeNumero[4]*pow(10,4)= 89999 :O :O ??????????
it has to be 90000 right??
in addition, I put some cout<< code, if u want to run this function and see how it works in my mind :P
but my question is: is there some bad code wrote by me or is some kind of bug or lack of knowledge?
void verificarPalindromo(int x)
{
int arregloDeNumero[6];
int diferencia=0;
for (int i=5;i>=0;i--){
cout << "the number X is: " << x;
cout << "and the difference is: " << diferencia << endl;
arregloDeNumero[i]= ((x-diferencia)/pow(10,i));
cout << "array of i= " << i << "is: " << arregloDeNumero[i];
cout << " and the difference is: " << diferencia << endl;
diferencia+=(arregloDeNumero[i]*pow(10,i));
cout << "the new difference is: " << diferencia << endl;
}
}
Although your code does not contain any floating point, the pow() function returns double and there seems to be a problem in your understanding of floating point numbers. It is frequently the case that dividing floating point numbers can result in a value that is very slightly different (perhaps only one bit) from the exact result. When such a value is converted to integer it is truncated and results in the next lower integer.
You should either
a) use a strategy that is entirely implemented using integers, or
b) use floating point, but ensure that conversions to int use rounding rather than truncation.
If you have a high enough warning level, the compiler should tell you about this potential problem.
Just to be clear, I would think the problem is here:
((x-diferencia)/pow(10,i))
The result of pow() for your integer arguments will be an integer value, but because the type is double the division is also double. It's floating point division that (usually) causes the problem of slight errors. It's possible the following change might fix it.
((x-diferencia)/(int)pow(10,i))

C++ Float Truncation & set precision logic error

I looked for a while and couldn't find an answer on here, but it seems to be a kind of weird question. I'm working with the fstream library in C++. What I'm trying to do is take data from an input file, assign it variables, and output this to both the screen and the output file. This is all for a project i'm working on that calculates the monthly payment of the car loan, which is why the variables are named the way they are.
My data file looks like this:
105670.00 12345.00 0.057 4
and essentially what is happening is I am losing everything after the decimal of the first two numbers (regardless of what i put as the decimal), but it doesn't happen to the 3rd number. additionally, when i try to setprecision(2) of the first two numbers i get a strange logic error, which i will show after my code.
my code looks like this:
#include<fstream>
#include<iomanip>
#include<iostream>
using namespace std;
int main ()
{
ifstream din; // These are my input and output files
ofstream dout;
float purchasePrice; // The first number of the input file.
float downPayment; // Second number.
float annualInterest; // Third number.
float numYears; // Last number.
// declaring the input/output files code here
din >> purchasePrice >> downPayment >> annualInterest >> numYears;
cout << purchasePrice << endl;
cout << downPayment << endl;
cout << annualInterest << endl;
cout << setprecision(2) << purchasePrice << endl;
cout << setprecision(2) << downPayment << endl;
cout << setprecison(2) << annualInterest << endl;
}
and here is my output:
105670
12345
0.057
1.1e+005
1.2e+004
0.057
I want my output to be:
105670.00
12345.00
0.057
105670.00
12345.00
0.05
Additionally, when performing any calculations, the numbers act as if they still have everything after the decimal. My question is, why are only some of the floats truncating, and why does setprecision() not work the way it is expected in this case?
Any responses are greatly appreciated, I'm sorry its such a lengthy explanation.
You also need to set the fmtflags to fixed:
std::cout << std::fixed << std::setprecision(2) << purchasePrice << "\n";
Without specifying scientific or fixed, the output mechanisms will use whatever scheme is deemed to be best. You know what's "best", and that's a fixed point scheme. For more detail, see http://en.cppreference.com/w/cpp/io/manip .
Even better is not to use floating point numbers at all when dealing with money. It is far better to use some fixed point arithmetic package.
float generally has 24 binary bits of precision which means that it can store about 6 decimal digits of precision so if your number is greater than 100000 you're not going to get any precision at all for decimal digits.
You should use double which has about 15 decimal digits of precision in this case instead of float
That answers your specific question most likely but if this is for money you probably shouldn't be using a floating format at all, as they can;t exactly represent 0.01 as a value for example, so all your calculations will be approximate and you probably don't want that when dealing with money. Generally hold the number of pence/cents/whatever in an integer and be careful :) Or even better a class specially designed for handling money values as there are often legal requirements on rounding etc.

Display a number decimal format instead as an exponential in cout

I calculated a total of floats and I got a number like 509990e-405. I'm assuming this is the short version; how can I cout this as a full number?
cout << NASATotal << endl;
is what I have now.
You can force the output to be not in scientific notation, and to have the sufficient precision to show your small number.
#include <iomanip>
// ...
long double d = 509990e-405L;
std::cout << std::fixed << std::setprecision(410) << d << std::endl;
Output:
0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050999000000
If you really want this is another question.
You can write your own BigNumber class that stores the results as strings. You would have to implement all of your numeric operations and I'm guessing performance will be an issue. But it can be done, no problem -- assuming that is what you want.

avoid rounding error (floating specifically) c++

http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/
I have been about this lately to review C++.
In general computing class professors tend not to cover these small things, although we knew what rounding errors meant.
Can someone please help me with how to avoid rounding error?
The tutorial shows a sample code
#include <iomanip>
int main()
{
using namespace std;
cout << setprecision(17);
double dValue = 0.1;
cout << dValue << endl;
}
This outputs
0.10000000000000001
By default float is kept 6-digits of precisions. Therefore, when we override the default, and asks for more (n this case, 17!!), we may encounter truncation (as explained by the tutorial as well).
For double, the highest is 16.
In general, how do good C++ programmers avoid rounding error?
Do you guys always look at the binary representation of the number?
Thank you.
The canonical advice for this topic is to read "What Every Computer Scientist Should Know About Floating-Point Arithmetic", by David Goldberg.
In other words, to minimize rounding errors, it can be helpful to keep numbers in decimal fixed-point (and actually work with integers).
#include <iostream>
#include <iomanip>
int main() {
using namespace std;
cout << setprecision(17);
double v1=1, v1D=10;
cout << v1/v1D << endl; // 0.10000000000000001
double v2=3, v2D=1000; //0.0030000000000000001
cout << v2/v2D << endl;
// v1/v1D + v2/v2D = (v1*v2D+v2*v1D)/(v1D*v2D)
cout << (v1*v2D+v2*v1D)/(v1D*v2D) << endl; // 0.10299999999999999
}
Short version - you can't really avoid rounding and other representation errors when you're trying to represent base 10 numbers in base 2 (ie, using a float or a double to represent a decimal number). You pretty much either have to work out how many significant digits you actually have or you have to switch to a (slower) arbitrary precision library.
Most floating point output routines look to see if the answer is very close to being even when represented in base 10 and round the answer to actually be even on output. By setting the precision in this way you are short-circuiting this process.
This rounding is done because almost no answer that comes out even in base 10 will be even (i.e. end in an infinite string of trailing 0s) in base 2, which is the base in which the number is represented internally. But, of course, the general goal of an output routine is to present the number in a fashion useful for a human being, and most human beings in the world today read numbers in base 10.
When you calculate simple thing like variance you can have this kind of problem... here is my solution...
int getValue(double val, int precision){
std::stringstream ss;
ss << val;
string strVal = ss.str();
size_t start = strVal.find(".");
std::string major = strVal.substr(0, start);
std::string minor = strVal.substr(start + 1);
// Fill whit zero...
while(minor.length() < precision){
minor += "0";
}
// Trim over precision...
if(minor.length() > precision){
minor = minor.substr(0, precision);
}
strVal = major + minor;
int intVal = atoi(strVal.c_str());
return intVal;
}
So you will make your calcul in the integer range...
for example 2523.49 became 252349 whit a precision of tow digits, and 2523490 whit a precision of tree digit... if you calculate the mean for example first you convert all value in integer, make the summation and get the result back in double, so you not accumulate error... Error are amplifie whit operation like square root and power function...
You want to use the manipulator called "Fixed" to format your digits correctly so they do not round or show in a scientific notation after you use fixed you will also be able to use set the precision() function to set the value placement to the right of the .
decimal point. the example would be as follows using your original code.
#include <iostream>
#include <iomanip>
int main()
{
using namespace std;
double dValue = 0.19213;
cout << fixed << setprecision(2) << dValue << endl;
}
outputs as:
dValue = 0.19