C++ decimal data types - c++

Is there a way to use decimal data types such as decimal32, decimal64 or decimal128in my C++ programs?

The classes from the Decimal TR are not implemented for all compilers. Some compilers, e.g., gcc, implement the C Decimal TR and provide the corresponding extensions in C++, too. In the past there was an open source implementation for the C++ Decimal TR available but I failed to locate it. If your compiler doesn't support the decimal types, your best option is probably to create a wrapper for IBM's decNumber library.
To improve the situation in the future of C++, I have created a plan to update the TR and I'm going to turn the current TR into a complete proposal ready for the next C++ committee meeting (in April in Bristol), trying to get it adopted into the C++ standard, possibly into the revision planned for 2014. The implementation I have is part of my regular work and it isn't up to me to decide whether it is can be made available publically although there is some hope that it can be open sourced at some point.

You can use easy to use header-only solution for C++ with templates:
https://github.com/vpiotr/decimal_for_cpp
Notice that this is not a *Big*Decimal class; it is limited to 64 bits' worth of "mantissa" digits.
[taken from link]
#include "decimal.h"
using namespace dec;
// the following declares currency variable with 2 decimal points
// initialized with integer value (can be also floating-point)
decimal<2> value(143125);
// to use non-decimal constants you need to convert them to decimal
value = value / decimal_cast<2>(333.0);
// output values
cout << "Result is: " << value << endl;
// this should display something like "429.80"
// to mix decimals with different precision use decimal_cast
decimal<6> exchangeRate(12.1234);
value = decimal_cast<2>(decimal_cast<6>(value) * exchangeRate);
cout << "Result 2 is: " << value << endl;
// this should display something like "5210.64"
cout << "Result 2<6> is: " << decimal_cast<6>(value) << endl;
// this should display something like "5210.640000"

use an int32 or int64, and (manually) shift the decimal point to where you want it to be. If you're measuring dollars, for example, just measure cents instead and display the value differently. simple!

Boost has cpp_dec_float as well. That's probably the best solution until it's adopted into the standard.
https://www.boost.org/doc/libs/1_68_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/cpp_dec_float.html
EDIT: This library uses floating point values in the implementation so is not a true decimal math library IMO.

gcc/clang (usually) come with their own floating point decimal implementations, if your distro decides to compile them into whatever gcc/clang version they offer (not the case for some arm distros I tried out). This is why you sometimes need a custom decimal type implementation. Try mine for ideas (tested on i586 all the way to aarch64).

decimal.h this library is not exit is is saying by my compiler.
/tmp/TQDyfEvEXQ.cpp:2:10: fatal error: decimal.h: No such file or directory
2 | #include <decimal.h>
| ^~~~~~~~~~~
compilation terminated.```

Related

cout causes compile error when using __float128 (error: ambiguous overload for ‘operator<<’) [duplicate]

In my question about Analysis of float/double precision in 32 decimal digits, one answer said to take a look at __float128.
I used it and the compiler could find it, but I can not print it, since the complier can not find the header quadmath.h.
So my questions are:
__float128 is standard, correct?
How to print it?
Isn't quadmath.h standard?
These answers did not help:
Use extern C
Precision in C++
Printing
The ref also did not help.
Note that I do not want to use any non standard library.
[EDIT]
It would be also useful, if that question had an answer, even if the answer was a negative one.
Work in GNU-Fortran! It allows to run the same program in different precision: single (32 bit), double (64 bit), extended (80 bit) and quad (128 bit). You don't have to do any changes in the program, you simply write 'real' for all floating points. The size of floating points is set by compiler options -freal-4-real-8, -freal-4-real-10 and -freal-4-real-16.
Using the boost library was the best answer for me:
#include <boost/multiprecision/float128.hpp>
#include <boost/math/special_functions/gamma.hpp>
using namespace boost::multiprecision;
float128 su1= 0.33333333333333333q;
cout << "su1=" << su1 << endl;
Remember to link this library:
-lquadmath
No, it's not standard - neither the type nor the header. That's why the type has a double underscore (reserved name). Apparently, quadmath.h provides a quadmath_snprintf method. In C++ you would have used <<, of course.

Why do I get platform-specific result for std::exp? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Math precision requirements of C and C++ standard
(1 answer)
Closed 4 years ago.
I have a program that were giving slithly different results under Android and Windows. As I validate the output data against a binary file containign expected result, the difference, even if very small (rounding issue) is annoying and I must find a way to fix it.
Here is a sample program:
#include <iostream>
#include <iomanip>
#include <bitset>
int main( int argc, char* argv[] )
{
// this value was identified as producing different result when used as parameter to std::exp function
unsigned char val[] = {158, 141, 250, 206, 70, 125, 31, 192};
double var = *((double*)val);
std::cout << std::setprecision(30);
std::cout << "var is " << var << std::endl;
double exp_var = std::exp(var);
std::cout << "std::exp(var) is " << exp_var << std::endl;
}
Under Windows, compiled with Visual 2015, I get the output:
var is -7.87234042553191493141184764681
std::exp(var) is 0.00038114128472300899284561093161
Under Android/armv7, compiled with g++ NDK r11b, I get the output:
var is -7.87234042553191493141184764681
std::exp(var) is 0.000381141284723008938635502307335
So the results are different starting e-20:
PC: 0.00038114128472300899284561093161
Android: 0.000381141284723008938635502307335
Note that my program does a lot of math operations and I only noticed std::exp producing different results for the same input...and only for some specific input values (did not investigate if those values are having a similar property), for most of them, results are identical.
Is this behaviour kind of "expected", is there no guarantee to have the same result in some situations?
Is there some compiler flag that could fix that?
Or do I need to round my result to end with the same on both platformas? Then what would be the good strategy for rounding? Because rounding abritrary at e-20 would loose too many information if input var in very small?
Edit: I consider my question not being a duplicate of Is floating point math broken?. I get exactly the same result on both platforms, only std::exp for some specific values produces different results.
The standard does not define how the exp function (or any other math library function1) should be implemented, thus each library implementation may use a different computing method.
For instance, the Android C library (bionic) uses an approximation of exp(r) by a special rational function on the interval [0,0.34658] and scales back the result.
Probably the Microsoft library is using a different computing method (cannot find info about it), thus resulting in different results.
Also the libraries could take a dynamic load strategy (i.e. load a .dll containing the actual implementation) in order to leverage the different hardware specific features, making it even more unpredictable the result, even when using the same compiler.
In order to get the same implementation in both (all) platforms, you could use your own implementation of the exp function, thus not relying on the different implementations of the different libraries.
Take into account that maybe the processors are taking different rounding approaches, which would yield also to a different result.
1 There are some exceptions to these, for isntance the sqrt function or std::fma and some rounding functions and basic arithmetic operations

Print __float128, without using quadmath_snprintf

In my question about Analysis of float/double precision in 32 decimal digits, one answer said to take a look at __float128.
I used it and the compiler could find it, but I can not print it, since the complier can not find the header quadmath.h.
So my questions are:
__float128 is standard, correct?
How to print it?
Isn't quadmath.h standard?
These answers did not help:
Use extern C
Precision in C++
Printing
The ref also did not help.
Note that I do not want to use any non standard library.
[EDIT]
It would be also useful, if that question had an answer, even if the answer was a negative one.
Work in GNU-Fortran! It allows to run the same program in different precision: single (32 bit), double (64 bit), extended (80 bit) and quad (128 bit). You don't have to do any changes in the program, you simply write 'real' for all floating points. The size of floating points is set by compiler options -freal-4-real-8, -freal-4-real-10 and -freal-4-real-16.
Using the boost library was the best answer for me:
#include <boost/multiprecision/float128.hpp>
#include <boost/math/special_functions/gamma.hpp>
using namespace boost::multiprecision;
float128 su1= 0.33333333333333333q;
cout << "su1=" << su1 << endl;
Remember to link this library:
-lquadmath
No, it's not standard - neither the type nor the header. That's why the type has a double underscore (reserved name). Apparently, quadmath.h provides a quadmath_snprintf method. In C++ you would have used <<, of course.

Understanding floating point variables and operators in c++ (Also a possible book error)

I am working through a beginning C++ class and my book(Starting Out with C++ Early Objects 7th edition) has a very poor example of how to check the value of a floating point variable.
The book example in question(filename pr4-04.cpp):
// This program demonstrates how to safely test a floating-point number
// to see if it is, for all practical purposes, equal to some value.
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double result = .666667 * 6.0;
// 2/3 of 6 should be 4 and, if you print result, 4 is displayed.
cout << "result = " << result << endl;
// However, internally result is NOT precisely equal to 4.
// So test to see if it is "close" to 4.
if (abs(result - 4.0 < .0001))
cout << "result DOES equal 4!" << endl;
else
cout << "result DOES NOT equal 4!" << endl;
return 0;
}
And I use g++ in Ubuntu to compile my code like this:
g++ pr4-04.cpp -o pr4-04 && ./pr4-04
And I get this error:
error: call of overloaded ‘abs(bool)’ is ambiguous
I am able to fix this by changing abs() to fabs(), but this is still super confusing! Why is the book giving us things which won't compile, or is this just me? Why does the cout of 'result' give 4 instead of 4.000002? Why does this value seem to change when it is used in the if{} statement?
I get that we can't just use == to check for equivalence, but why do I need to use the absolute value? I get the same answer whether or not I use it. So what is the point?
Not to mention, this seems like a very poor way to check for floating point equivalence. Is there a better way to do this? This topic seems awfully important.
I found this topic here on stackoverflow, but their solution:
fabs(f1 - f2) < precision-requirement
fabs(f1 - f2) < max(fabs(f1), fabs(f2)) * percentage-precision-requirement
Doesn't make much sense to me in the context of my 4 chapters worth of C++ experience. I would greatly appreciate some help. Our book has given me a whopping 6 sentences of text to explain all of this.
Edit: As suggested by some I tried to find an errata page, but after 30mins of searching the textbook, internet, and my course website I was only able to find this downloadable zip file, which required a login -_-
I also copied the code perfectly. That was not MY typo, I copied it directly from a CD with the code on it. It is also typed that way in the book.
if (abs(result - 4.0 < .0001))
The parenthesis are wrong, you probably mean: if (abs(result-4.0) < .0001).
As to why it did not compile, the standard determines in §26.8p8 that
In addition to the double versions of the math functions in , C++ adds float and long double overloaded versions of these functions, with the same semantics.
The expression (result-4.0 < .0001) yields a bool, and there is no overload of abs that takes a bool argument, but there are multiple versions of abs for which the argument is implicitly convertible from bool. The compiler does not find one of the conversion sequences better than the rest and bails out with the ambiguity error.
The problem is clearly the line
if (abs(result - 4.0 < .0001))
which should be written as
if (abs(result - 4.0) < .0001)
I would assume that this is a simple typo. Report the error to the author of the book!
BTW, the original code does compile on my system without any problem, giving the expected result! That is, even if the author tested the code he may not have noticed that it is problematic!
Also answering the question on why abs() is needed: some decimal numbers are rounded to a floating point value which is slightly smaller than the expected result while others are rounded to number which are slightly bigger. In which direction the values are round (if at all: some decimal numbers can be represented exactly using binary floating points) is somewhat hard to predict. Thus, the result may be slightly bigger or slightly smaller than the expectation and the difference, thus, positive or negative, respectively.

Incorrect results from C++ math library's trigonometry functions

I'm currently working on a personal project that I've been doing for nearly a year now. I am trying to port it over to a Windows environment, which has succeeded. Because I am trying to get a Windows version out to people soon, I decided to continue to develop in Windows while I try to add new features and get bugs that have existed for months out. While recently attempting to add functionality which relied heavily on trigonometry, I found that all 3 trigonometric functions, oddly enough, returned the same value (1072693887) regardless of the parameter I passed. As you can imagine, this is leading to some rather strange bugs in the system.
I have math.h included, and to my knowledge no other files that would contain this function. (Perhaps there's a debugger command to find where a symbol is defined? I couldn't find any such thing, but perhaps I missed something.) I've tried asking elsewhere and searching around on Google, but to no avail...
Has anyone else heard of this problem before, or know how to fix it?
EDIT : This answer is not relevant. See comments.
This is probably due to numerical instability.
When you pass such a large value into sin(), cos(), or any of the periodic trig functions, you have to remember that there's an implicit modulo by 2*pi.
If you are using float, then the uncertainty of 1072693887, is way more than 2*pi. Therefore, whatever result you get is garbage.
We'll need to see some code to be able to see exactly what's going on though.
EDIT : Here's an illustration:
sin(1072693886) = 0.6783204666
sin(1072693887) = -0.2517863119
sin(1072693888) = -0.9504019164
But if the datatype is float, then the uncertainty of 1072693887 is +/- ~64...
1072693887 is 3FF207FF in hexadecimal, which represents 1.8908690 in IEEE single precision floating point. Are you sure your problem isn't just a representation one, ie you are casting or view the result as a integer?
All I know is that GDB is telling me the result of it is 1072693887, that it's occurring with all 3 of my trig functions (and that the arc versions of all three of them just return -1072693887) regardless of what parameter I pass.
Might be a GDB issue. What happens if you just manually print the values to the console?
Math library is fine.
You realize that the functions expect radians as input right?
E.g. :
double param = 90.0;
double rads = param * M_PI/180;
std::cout << std::fixed << "Angle : " << param << " sin : " << sin (rads) << " cos " << cos(rads);
Output :
Angle : 90.000000 sin : 1.000000 cos 0.000000-0.304811