What does "double + 1e-6" mean? - c++

The result of this cpp is 72.740, but the answer should be like 72.741
mx = 72.74050000;
printf("%.3lf \n", mx);
So I found the solution on website, and it told me to add "+1e-7" and it works
mx = 72.74050000;
printf("%.3lf \n", mx + 1e-7);
but I dont know the reason in this method, can anyone explain how it works?
And I also try to print it but nothing special happens..., and it turn out to be 72.7405
mx = 72.74050003;
cout << mx + 1e-10;

To start, your question contains an incorrect assumption. You put 72.7405 (let's assume it's precise) on input and expect 72.741 on output. So, you assume that rounding in printf will select higher candidate of possible twos. Why?
Well, one could consider this is your task, according to some rules (e.g. fiscal norms for rounding in bills, in taxation, etc.) - this is usual. But, when you use standard de facto floating of C/C++ on x86, ARM, etc., you should take the following specifics into account:
It is binary, not decimal. As result, all values you showed in your example are kept with some error.
Standard library tends to use standard rounding, unless forced to use another method.
The second point means that default rounding in C floating is round-to-nearest-ties-to-even (or, shortly, half-to-even). With this rounding, 72.7405 will be rounded to 72.740, not 72.741 (but, 72.7415 will be rounded to 72.742). To ask for rounding 72.7405 -> 72.741, you should have installed another rounding mode: round-to-nearest-ties-away-from-zero (shortly: round-half-away). This mode is request, to refer to, in IEEE754 for decimal arithmetic. So, if you used true decimal arithmetic, it would suffice.
(If we don't allow negative numbers, the same mode might be treated as half-up. But I assume negative numbers are not permitted in financial accounting and similar contexts.)
But, the first point here is more important: inexactness of representation of such values can be multiplied by operations. I repeat your situation and a proposed solution with more cases:
Code:
#include <stdio.h>
int main()
{
float mx;
mx = 72.74050000;
printf("%.6lf\n", mx);
printf("%.3lf\n", mx + 1e-7);
mx *= 3;
printf("%.6lf\n", mx);
printf("%.3lf\n", mx + 1e-7);
}
Result (Ubuntu 20.04/x86-64):
72.740501
72.741
218.221497
218.221
So you see that just multiplying of your example number by 3 resulted in situation that the compensation summand 1e-7 gets not enough to force rounding half-up, and 218.2215 (the "exact" 72.7405*3) is rounded to 218.221 instead of desired 218.222. Oops, "Directed by Robert B. Weide"...
How the situation could be fixed? Well, you could start with a stronger rough approach. If you need rounding to 3 decimal digits, but inputs look like having 4 digits, add 0.00005 (half of least significant digit in your results) instead of this powerless and sluggish 1e-7. This will definitely move half-voting values up.
But, all this will work only if result before rounding have error strictly less than 0.00005. If you have cumbersome calculations (e.g. summing hundreds of values), it's easy to get resulting error more than this threshold. To avoid such an error, you would round intermediate results often (ideally, each value).
And, the last conclusion leads us to the final question: if we need to round each intermediate result, why not just migrate to calculations in integers? You have to keep intermediate results up to 4 decimal digits? Scale by 10000 and do all calculations in integers. This will also aid in avoiding silent(*) accuracy loss with higher exponents.
(*) Well, IEEE754 requires raising "inexact" flag, but, with binary floating, nearly any operation with decimal fractions will raise it, so, useful signal will drown in sea of noise.
The final conclusion is the proper answer not to your question but to upper task: use fixed-point approaches. The approach with this +1e-7, as I showed above, is too easy to fail. No, don't use it, no, never. There are lots of proper libraries for fixed-point arithmetic, just pick one and use.
(It's also interesting why %.6f resulted in printing 72.740501 but 218.221497/3 == 72.740499. It suggests "single" floating (float in C) gets too inaccurate here. Even without this wrong approach, using double will postpone the issue, masking it and disguising as a correct way.)

If you will output the value like
printf( "mx = %.16f\n", mx );
you will see
mx = 72.7404999999999973
So to make the result like 72.741 due to rounding in outputting with a call of printf you need to make the next digit equal to 5 instead of 4. It is enough to add 0.00001.
Here is a demonstration program.
#include <iostream>
#include <iomanip>
#include <cstdio>
int main( void )
{
double mx = 72.74050000;
printf( "mx = %.3f\n", mx + 0.00001);
std::cout << "mx = " << std::setprecision( 5 ) << mx + 0.00001 << '\n';
}
The program output is
mx = 72.741
mx = 72.741
0.00001 is the same as 1e-5.

Related

What data type, scheme, and how many bits should be used to store a FOREX price? [duplicate]

I know that a float isn't appropriate to store currency values because of rounding errors. Is there a standard way to represent money in C++?
I've looked in the boost library and found nothing about it. In java, it seems that BigInteger is the way but I couldn't find an equivalent in C++. I could write my own money class, but prefer not to do so if there is something tested.
Don't store it just as cents, since you'll accumulate errors when multiplying for taxes and interest pretty quickly. At the very least, keep an extra two significant digits: $12.45 would be stored as 124,500. If you keep it in a signed 32 bit integer, you'll have $200,000 to work with (positive or negative). If you need bigger numbers or more precision, a signed 64 bit integer will likely give you all the space you'll need for a long time.
It might be of some help to wrap this value in a class, to give you one place for creating these values, doing arithmetic on them, and formatting them for display. This would also give you a central place to carry around which currency it being stored (USD, CAD, EURO, etc).
Having dealt with this in actual financial systems, I can tell you you probably want to use a number with at least 6 decimal places of precision (assuming USD). Hopefully since you're talking about currency values you won't go way out of whack here. There are proposals for adding decimal types to C++, but I don't know of any that are actually out there yet.
The best native C++ type to use here would be long double.
The problem with other approaches that simply use an int is that you have to store more than just your cents. Often financial transactions are multiplied by non-integer values and that's going to get you in trouble since $100.25 translated to 10025 * 0.000123523 (e.g. APR) is going cause problems. You're going to eventually end up in floating point land and the conversions are going to cost you a lot.
Now the problem doesn't happen in most simple situations. I'll give you a precise example:
Given several thousand currency values, if you multiply each by a percentage and then add them up, you will end up with a different number than if you had multiplied the total by that percentage if you do not keep enough decimal places. Now this might work in some situations, but you'll often be several pennies off pretty quickly. In my general experience making sure you keep a precision of up to 6 decimal places (making sure that the remaining precision is available for the whole number part).
Also understand that it doesn't matter what type you store it with if you do math in a less precise fashion. If your math is being done in single precision land, then it doesn't matter if you're storing it in double precision. Your precision will be correct to the least precise calculation.
Now that said, if you do no math other than simple addition or subtraction and then store the number then you'll be fine, but as soon as anything more complex than that shows up, you're going to be in trouble.
Look in to the relatively recent Intelr Decimal Floating-Point Math Library. It's specifically for finance applications and implements some of the new standards for binary floating point arithmetic (IEEE 754r).
The biggest issue is rounding itself!
19% of 42,50 € = 8,075 €. Due to the German rules for rounding this is 8,08 €. The problem is, that (at least on my machine) 8,075 can't be represented as double. Even if I change the variable in the debugger to this value, I end up with 8,0749999....
And this is where my rounding function (and any other on floating point logic that I can think of) fails, since it produces 8,07 €. The significant digit is 4 and so the value is rounded down. And that is plain wrong and you can't do anything about it unless you avoid using floating point values wherever possible.
It works great if you represent 42,50 € as Integer 42500000.
42500000 * 19 / 100 = 8075000. Now you can apply the rounding rule above 8080000. This can easily be transformed to a currency value for display reasons. 8,08 €.
But I would always wrap that up in a class.
I would suggest that you keep a variable for the number of cents instead of dollars. That should remove the rounding errors. Displaying it in the standards dollars/cents format should be a view concern.
You can try decimal data type:
https://github.com/vpiotr/decimal_for_cpp
Designed to store money-oriented values (money balance, currency rate, interest rate), user-defined precision. Up to 19 digits.
It's header-only solution for C++.
You say you've looked in the boost library and found nothing about there.
But there you have multiprecision/cpp_dec_float which says:
The radix of this type is 10. As a result it can behave subtly differently from base-2 types.
So if you're already using Boost, this should be good to currency values and operations, as its base 10 number and 50 or 100 digits precision (a lot).
See:
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_dec_float.hpp>
int main()
{
float bogus = 1.0 / 3.0;
boost::multiprecision::cpp_dec_float_50 correct = 1.0 / 3.0;
std::cout << std::setprecision(16) << std::fixed
<< "float: " << bogus << std::endl
<< "cpp_dec_float: " << correct << std::endl;
return 0;
}
Output:
float: 0.3333333432674408
cpp_dec_float: 0.3333333333333333
*I'm not saying float (base 2) is bad and decimal (base 10) is good. They just behave differently...
** I know this is an old post and boost::multiprecision was introduced in 2013, so wanted to remark it here.
Know YOUR range of data.
A float is only good for 6 to 7 digits of precision, so that means a max of about +-9999.99 without rounding. It is useless for most financial applications.
A double is good for 13 digits, thus: +-99,999,999,999.99, Still be careful when using large numbers. Recognize the subtracting two similar results strips away much of the precision (See a book on Numerical Analysis for potential problems).
32 bit integer is good to +-2Billion (scaling to pennies will drop 2 decimal places)
64 bit integer will handle any money, but again, be careful when converting, and multiplying by various rates in your app that might be floats/doubles.
The key is to understand your problem domain. What legal requirements do you have for accuracy? How will you display the values? How often will conversion take place? Do you need internationalization? Make sure you can answer these questions before you make your decision.
Whatever type you do decide on, I would recommend wrapping it up in a "typedef" so you can change it at a different time.
It depends on your business requirements with regards to rounding. The safest way is to store an integer with the required precision and know when/how to apply rounding.
Store the dollar and cent amount as two separate integers.
Integers, always--store it as cents (or whatever your lowest currency is where you are programming for.) The problem is that no matter what you do with floating point someday you'll find a situation where the calculation will differ if you do it in floating point. Rounding at the last minute is not the answer as real currency calculations are rounded as they go.
You can't avoid the problem by changing the order of operations, either--this fails when you have a percentage that leaves you without a proper binary representation. Accountants will freak if you are off by a single penny.
I would recommend using a long int to store the currency in the smallest denomination (for example, American money would be cents), if a decimal based currency is being used.
Very important: be sure to name all of your currency values according to what they actually contain. (Example: account_balance_cents) This will avoid a lot of problems down the line.
(Another example where this comes up is percentages. Never name a value "XXX_percent" when it actually contains a ratio not multiplied by a hundred.)
The solution is simple, store to whatever accuracy is required, as a shifted integer. But when reading in convert to a double float, so that calculations suffer fewer rounding errors. Then when storing in the database multiply to whatever integer accuracy is needed, but before truncating as an integer add +/- 1/10 to compensate for truncation errors, or +/- 51/100 to round.
Easy peasy.
The GMP library has "bignum" implementations that you can use for arbitrary sized integer calculations needed for dealing with money. See the documentation for mpz_class (warning: this is horribly incomplete though, full range of arithmetic operators are provided).
One option is to store $10.01 as 1001, and do all calculations in pennies, dividing by 100D when you display the values.
Or, use floats, and only round at the last possible moment.
Often the problems can be mitigated by changing order of operations.
Instead of value * .10 for a 10% discount, use (value * 10)/100, which will help significantly. (remember .1 is a repeating binary)
I'd use signed long for 32-bit and signed long long for 64-bit. This will give you maximum storage capacity for the underlying quantity itself. I would then develop two custom manipulators. One that converts that quantity based on exchange rates, and one that formats that quantity into your currency of choice. You can develop more manipulators for various financial operations / and rules.
This is a very old post, but I figured I update it a little since it's been a while and things have changed. I have posted some code below which represents the best way I have been able to represent money using the long long integer data type in the C programming language.
#include <stdio.h>
int main()
{
// make BIG money from cents and dollars
signed long long int cents = 0;
signed long long int dollars = 0;
// get the amount of cents
printf("Enter the amount of cents: ");
scanf("%lld", &cents);
// get the amount of dollars
printf("Enter the amount of dollars: ");
scanf("%lld", &dollars);
// calculate the amount of dollars
long long int totalDollars = dollars + (cents / 100);
// calculate the amount of cents
long long int totalCents = cents % 100;
// print the amount of dollars and cents
printf("The total amount is: %lld dollars and %lld cents\n", totalDollars, totalCents);
}
As other answers have pointed out, you should either:
Use an integer type to store whole units of your currency (ex: $1) and fractional units (ex: 10 cents) separately.
Use a base 10 decimal data type that can exactly represent real decimal numbers such as 0.1. This is important since financial calculations are based on a base 10 number system.
The choice will depend on the problem you are trying to solve. For example, if you only need to add or subtract currency values then the integer approach might be sensible. If you are building a more complex system dealing with financial securities then the decimal data type approach may be more appropriate.
As another answer points out, Boost provides a base 10 floating point number type that serves as a drop-in replacement for the native C++ floating-point types, but with much greater precision. This might be convenient to use if your project already uses other Boost libraries.
The following example shows how to properly use this decimal type:
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
using namespace std;
using namespace boost::multiprecision;
int main() {
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::max_digits10) << std::endl;
double d1 = 1.0 / 10.0;
cpp_dec_float_50 dec_incorrect = 1.0 / 10.0; // Incorrect! We are constructing our decimal data type from the binary representation of the double value of 1.0 / 10.0
cpp_dec_float_50 dec_correct(cpp_dec_float_50(1.0) / 10.0);
cpp_dec_float_50 dec_correct2("0.1"); // Constructing from a decimal digit string.
std::cout << d1 << std::endl; // 0.1000000000000000055511151231257827021181583404541015625
std::cout << dec_incorrect << std::endl; // 0.1000000000000000055511151231257827021181583404541015625
std::cout << dec_correct << std::endl; // 0.1
std::cout << dec_correct2 << std::endl; // 0.1
return 0;
}
Notice how even if we define a decimal data type but construct it from a binary representation of a double, then we will not obtain the precision that we expect. In the example above, both the double d1 and the cpp_dec_float_50 dec_incorrect are the same because of this. Notice how they are both "correct" to about 17 decimal places which is what we would expect of a double in a 64-bit system.
Finally, note that the boost multiprecision library can be significantly slower than the fastest high precision implementations available. This becomes evident at high digit counts (about 50+); at low digit counts the Boost implementation can be comparable other, faster implementations.
Sources:
https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/fp_eg/floatbuiltinctor.html
https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/fp_eg/caveats.html
Our financial institution uses "double". Since we're a "fixed income" shop, we have lots of nasty complicated algorithms that use double anyway. The trick is to be sure that your end-user presentation does not overstep the precision of double. For example, when we have a list of trades with a total in trillions of dollars, we got to be sure that we don't print garbage due to rounding issues.
go ahead and write you own money (http://junit.sourceforge.net/doc/testinfected/testing.htm) or currency () class (depending on what you need). and test it.

XCODE C++ Decimal/Money data type? [duplicate]

I know that a float isn't appropriate to store currency values because of rounding errors. Is there a standard way to represent money in C++?
I've looked in the boost library and found nothing about it. In java, it seems that BigInteger is the way but I couldn't find an equivalent in C++. I could write my own money class, but prefer not to do so if there is something tested.
Don't store it just as cents, since you'll accumulate errors when multiplying for taxes and interest pretty quickly. At the very least, keep an extra two significant digits: $12.45 would be stored as 124,500. If you keep it in a signed 32 bit integer, you'll have $200,000 to work with (positive or negative). If you need bigger numbers or more precision, a signed 64 bit integer will likely give you all the space you'll need for a long time.
It might be of some help to wrap this value in a class, to give you one place for creating these values, doing arithmetic on them, and formatting them for display. This would also give you a central place to carry around which currency it being stored (USD, CAD, EURO, etc).
Having dealt with this in actual financial systems, I can tell you you probably want to use a number with at least 6 decimal places of precision (assuming USD). Hopefully since you're talking about currency values you won't go way out of whack here. There are proposals for adding decimal types to C++, but I don't know of any that are actually out there yet.
The best native C++ type to use here would be long double.
The problem with other approaches that simply use an int is that you have to store more than just your cents. Often financial transactions are multiplied by non-integer values and that's going to get you in trouble since $100.25 translated to 10025 * 0.000123523 (e.g. APR) is going cause problems. You're going to eventually end up in floating point land and the conversions are going to cost you a lot.
Now the problem doesn't happen in most simple situations. I'll give you a precise example:
Given several thousand currency values, if you multiply each by a percentage and then add them up, you will end up with a different number than if you had multiplied the total by that percentage if you do not keep enough decimal places. Now this might work in some situations, but you'll often be several pennies off pretty quickly. In my general experience making sure you keep a precision of up to 6 decimal places (making sure that the remaining precision is available for the whole number part).
Also understand that it doesn't matter what type you store it with if you do math in a less precise fashion. If your math is being done in single precision land, then it doesn't matter if you're storing it in double precision. Your precision will be correct to the least precise calculation.
Now that said, if you do no math other than simple addition or subtraction and then store the number then you'll be fine, but as soon as anything more complex than that shows up, you're going to be in trouble.
Look in to the relatively recent Intelr Decimal Floating-Point Math Library. It's specifically for finance applications and implements some of the new standards for binary floating point arithmetic (IEEE 754r).
The biggest issue is rounding itself!
19% of 42,50 € = 8,075 €. Due to the German rules for rounding this is 8,08 €. The problem is, that (at least on my machine) 8,075 can't be represented as double. Even if I change the variable in the debugger to this value, I end up with 8,0749999....
And this is where my rounding function (and any other on floating point logic that I can think of) fails, since it produces 8,07 €. The significant digit is 4 and so the value is rounded down. And that is plain wrong and you can't do anything about it unless you avoid using floating point values wherever possible.
It works great if you represent 42,50 € as Integer 42500000.
42500000 * 19 / 100 = 8075000. Now you can apply the rounding rule above 8080000. This can easily be transformed to a currency value for display reasons. 8,08 €.
But I would always wrap that up in a class.
I would suggest that you keep a variable for the number of cents instead of dollars. That should remove the rounding errors. Displaying it in the standards dollars/cents format should be a view concern.
You can try decimal data type:
https://github.com/vpiotr/decimal_for_cpp
Designed to store money-oriented values (money balance, currency rate, interest rate), user-defined precision. Up to 19 digits.
It's header-only solution for C++.
You say you've looked in the boost library and found nothing about there.
But there you have multiprecision/cpp_dec_float which says:
The radix of this type is 10. As a result it can behave subtly differently from base-2 types.
So if you're already using Boost, this should be good to currency values and operations, as its base 10 number and 50 or 100 digits precision (a lot).
See:
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_dec_float.hpp>
int main()
{
float bogus = 1.0 / 3.0;
boost::multiprecision::cpp_dec_float_50 correct = 1.0 / 3.0;
std::cout << std::setprecision(16) << std::fixed
<< "float: " << bogus << std::endl
<< "cpp_dec_float: " << correct << std::endl;
return 0;
}
Output:
float: 0.3333333432674408
cpp_dec_float: 0.3333333333333333
*I'm not saying float (base 2) is bad and decimal (base 10) is good. They just behave differently...
** I know this is an old post and boost::multiprecision was introduced in 2013, so wanted to remark it here.
Know YOUR range of data.
A float is only good for 6 to 7 digits of precision, so that means a max of about +-9999.99 without rounding. It is useless for most financial applications.
A double is good for 13 digits, thus: +-99,999,999,999.99, Still be careful when using large numbers. Recognize the subtracting two similar results strips away much of the precision (See a book on Numerical Analysis for potential problems).
32 bit integer is good to +-2Billion (scaling to pennies will drop 2 decimal places)
64 bit integer will handle any money, but again, be careful when converting, and multiplying by various rates in your app that might be floats/doubles.
The key is to understand your problem domain. What legal requirements do you have for accuracy? How will you display the values? How often will conversion take place? Do you need internationalization? Make sure you can answer these questions before you make your decision.
Whatever type you do decide on, I would recommend wrapping it up in a "typedef" so you can change it at a different time.
It depends on your business requirements with regards to rounding. The safest way is to store an integer with the required precision and know when/how to apply rounding.
Store the dollar and cent amount as two separate integers.
Integers, always--store it as cents (or whatever your lowest currency is where you are programming for.) The problem is that no matter what you do with floating point someday you'll find a situation where the calculation will differ if you do it in floating point. Rounding at the last minute is not the answer as real currency calculations are rounded as they go.
You can't avoid the problem by changing the order of operations, either--this fails when you have a percentage that leaves you without a proper binary representation. Accountants will freak if you are off by a single penny.
I would recommend using a long int to store the currency in the smallest denomination (for example, American money would be cents), if a decimal based currency is being used.
Very important: be sure to name all of your currency values according to what they actually contain. (Example: account_balance_cents) This will avoid a lot of problems down the line.
(Another example where this comes up is percentages. Never name a value "XXX_percent" when it actually contains a ratio not multiplied by a hundred.)
The solution is simple, store to whatever accuracy is required, as a shifted integer. But when reading in convert to a double float, so that calculations suffer fewer rounding errors. Then when storing in the database multiply to whatever integer accuracy is needed, but before truncating as an integer add +/- 1/10 to compensate for truncation errors, or +/- 51/100 to round.
Easy peasy.
The GMP library has "bignum" implementations that you can use for arbitrary sized integer calculations needed for dealing with money. See the documentation for mpz_class (warning: this is horribly incomplete though, full range of arithmetic operators are provided).
One option is to store $10.01 as 1001, and do all calculations in pennies, dividing by 100D when you display the values.
Or, use floats, and only round at the last possible moment.
Often the problems can be mitigated by changing order of operations.
Instead of value * .10 for a 10% discount, use (value * 10)/100, which will help significantly. (remember .1 is a repeating binary)
I'd use signed long for 32-bit and signed long long for 64-bit. This will give you maximum storage capacity for the underlying quantity itself. I would then develop two custom manipulators. One that converts that quantity based on exchange rates, and one that formats that quantity into your currency of choice. You can develop more manipulators for various financial operations / and rules.
This is a very old post, but I figured I update it a little since it's been a while and things have changed. I have posted some code below which represents the best way I have been able to represent money using the long long integer data type in the C programming language.
#include <stdio.h>
int main()
{
// make BIG money from cents and dollars
signed long long int cents = 0;
signed long long int dollars = 0;
// get the amount of cents
printf("Enter the amount of cents: ");
scanf("%lld", &cents);
// get the amount of dollars
printf("Enter the amount of dollars: ");
scanf("%lld", &dollars);
// calculate the amount of dollars
long long int totalDollars = dollars + (cents / 100);
// calculate the amount of cents
long long int totalCents = cents % 100;
// print the amount of dollars and cents
printf("The total amount is: %lld dollars and %lld cents\n", totalDollars, totalCents);
}
As other answers have pointed out, you should either:
Use an integer type to store whole units of your currency (ex: $1) and fractional units (ex: 10 cents) separately.
Use a base 10 decimal data type that can exactly represent real decimal numbers such as 0.1. This is important since financial calculations are based on a base 10 number system.
The choice will depend on the problem you are trying to solve. For example, if you only need to add or subtract currency values then the integer approach might be sensible. If you are building a more complex system dealing with financial securities then the decimal data type approach may be more appropriate.
As another answer points out, Boost provides a base 10 floating point number type that serves as a drop-in replacement for the native C++ floating-point types, but with much greater precision. This might be convenient to use if your project already uses other Boost libraries.
The following example shows how to properly use this decimal type:
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
using namespace std;
using namespace boost::multiprecision;
int main() {
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::max_digits10) << std::endl;
double d1 = 1.0 / 10.0;
cpp_dec_float_50 dec_incorrect = 1.0 / 10.0; // Incorrect! We are constructing our decimal data type from the binary representation of the double value of 1.0 / 10.0
cpp_dec_float_50 dec_correct(cpp_dec_float_50(1.0) / 10.0);
cpp_dec_float_50 dec_correct2("0.1"); // Constructing from a decimal digit string.
std::cout << d1 << std::endl; // 0.1000000000000000055511151231257827021181583404541015625
std::cout << dec_incorrect << std::endl; // 0.1000000000000000055511151231257827021181583404541015625
std::cout << dec_correct << std::endl; // 0.1
std::cout << dec_correct2 << std::endl; // 0.1
return 0;
}
Notice how even if we define a decimal data type but construct it from a binary representation of a double, then we will not obtain the precision that we expect. In the example above, both the double d1 and the cpp_dec_float_50 dec_incorrect are the same because of this. Notice how they are both "correct" to about 17 decimal places which is what we would expect of a double in a 64-bit system.
Finally, note that the boost multiprecision library can be significantly slower than the fastest high precision implementations available. This becomes evident at high digit counts (about 50+); at low digit counts the Boost implementation can be comparable other, faster implementations.
Sources:
https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/fp_eg/floatbuiltinctor.html
https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/fp_eg/caveats.html
Our financial institution uses "double". Since we're a "fixed income" shop, we have lots of nasty complicated algorithms that use double anyway. The trick is to be sure that your end-user presentation does not overstep the precision of double. For example, when we have a list of trades with a total in trillions of dollars, we got to be sure that we don't print garbage due to rounding issues.
go ahead and write you own money (http://junit.sourceforge.net/doc/testinfected/testing.htm) or currency () class (depending on what you need). and test it.

c++ Floating point subtraction error and absolute values

The way I understand it is: when subtracting two double numbers with double precision in c++ they are first transformed to a significand starting with one times 2 to the power of the exponent. Then one can get an error if the subtracted numbers have the same exponent and many of the same digits in the significand, leading to loss of precision. To test this for my code I wrote the following safe addition function:
double Sadd(double d1, double d2, int& report, double prec) {
int exp1, exp2;
double man1=frexp(d1, &exp1), man2=frexp(d2, &exp2);
if(d1*d2<0) {
if(exp1==exp2) {
if(abs(man1+man2)<prec) {
cout << "Floating point error" << endl;
report=0;
}
}
}
return d1+d2;
}
However, testing this I notice something strange: it seems that the actual error (not whether the function reports error but the actual one resulting from the computation) seems to depend on the absolute values of the subtracted numbers and not just the number of equal digits in the significand...
For examples, using 1e-11 as the precision prec and subtracting the following numbers:
1) 9.8989898989898-9.8989898989897: The function reports error and I get the highly incorrect value 9.9475983006414e-14
2) 98989898989898-98989898989897: The function reports error but I get the correct value 1
Obviously I have misunderstood something. Any ideas?
If you subtract two floating-point values that are nearly equal, the result will mostly reflect noise in the low bits. Nearly equal here is more than just same exponent and almost the same digits. For example, 1.0001 and 1.0000 are nearly equal, and subtracting them could be caught by a test like this. But 1.0000 and 0.9999 differ by exactly the same amount, and would not be caught by a test like this.
Further, this is not a safe addition function. Rather, it's a post-hoc check for a design/coding error. If you're subtracting two values that are so close together that noise matters you've made a mistake. Fix the mistake. I'm not objecting to using something like this as a debugging aid, but please call it something that implies that that's what it is, rather than suggesting that there's something inherently dangerous about floating-point addition. Further, putting the check inside the addition function seems excessive: an assert that the two values won't cause problems, followed by a plain old floating-point addition, would probably be better. After all, most of the additions in your code won't lead to problems, and you'd better know where the problem spots are; put asserts in the problems spots.
+1 to Pete Becker's answer.
Note that the problem of degenerated result might also occur with exp1!=exp2
For example, if you subtract
1.0-0.99999999999999
So,
bool degenerated =
(epx1==exp2 && abs(d1+d2)<prec)
|| (epx1==exp2-1 && abs(d1+2*d2)<prec)
|| (epx1==exp2+1 && abs(2*d1+d2)<prec);
You can omit the check for d1*d2<0, or keep it to avoid the whole test otherwise...
If you want to also handle loss of precision with degenerated denormalized floats, that'll be a bit more involved (it's as if the significand had less bits).
It's quite easy to prove that for IEEE 754 floating-point arithmetic, if x/2 <= y <= 2x then calculating x - y is an exact operation and will give the exact result correctly without any rounding error.
And if the result of an addition or subtraction is a denormalised number, then the result is always exact.

How can I work around the fact that in C++, sin(M_PI) is not 0?

In C++,
const double Pi = 3.14159265;
cout << sin(Pi); // displays: 3.58979e-009
it SHOULD display the number zero
I understand this is because Pi is being approximated, but is there any way I can have a value of Pi hardcoded into my program that will return 0 for sin(Pi)? (a different constant maybe?)
In case you're wondering what I'm trying to do: I'm converting polar to rectangular, and while there are some printf() tricks I can do to print it as "0.00", it still doesn't consistently return decent values (in some cases I get "-0.00")
The lines that require sin and cosine are:
x = r*sin(theta);
y = r*cos(theta);
BTW: My Rectangular -> Polar is working fine... it's just the Polar -> Rectangular
Thanks!
edit: I'm looking for a workaround so that I can print sin(some multiple of Pi) as a nice round number to the console (ideally without a thousand if-statements)
What Every Computer Scientist Should Know About Floating-Point Arithmetic (edit: also got linked in a comment) is pretty hardcore reading (I can't claim to have read all of it), but the crux of it is this: you'll never get perfectly accurate floating point calculations. From the article:
Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation.
Don't let your program depend on exact results from floating point calculations - always allow a tolerance range. FYI 3.58979e-009 is about 0.0000000036. That's well within any reasonable tolerance range you choose!
Let's put it this way, 3.58979e-009 is as close to 0 as your 3.14159265 value is to the real Pi. What you got is, technically, what you asked for. :)
Now, if you only put 9 significant figures (8 decimal places) in, then instruct the output to also display no more, i.e. use:
cout.precision(8);
cout << sin(Pi);
it's equal to zero if your equality operator has enough tolerance
Did you try M_PI, available in most <cmath> or <math.h> implementations?
Even so, using floating point in this way will always introduce a certain amount of error.
This should display zero:
cout << fixed << sin(Pi);
(I don't think you should be trying to round anything. If you are worried about display, deal with the display functions, not with the value itself.)
3.58979e-009 this is 0,0000000358979
Is a ~~0 like yours ~~PI.
You could throw in some more digits to get a better result (try for example 3.1415926535897932384626433832795029L), but you'll still get rounding errors.
Still, you can create your own sin and cos versions that check against your known Pi value and return exactly zero in those cases.
namespace TrigExt
{
const double PI = 3.14159265358979323846;
inline double sin(double theta)
{
return theta==PI?(0.0):(std::sin(theta));
}
}
You may also expand this thing for the other trigonometric functions and to handle Pi multiples.
You could write a little wrapper function:
double mysin(const double d) {
double ret = sin(d);
if(fabs(ret) < 0.0000001) {
return 0.0;
} else {
return ret;
}
}
As others have noted, floating-point maths is notoriously inexact. You need some kind of tolerance if you want something to appear as exactly zero.
why not force to however many digits you need
int isin = (int)(sin(val) * 1000);
cout << (isin/1000.0)
sin(PI) should equal 0, for an exact value of PI. You are not entering the exact value of PI. As other people are pointing out, the result you are getting rounded to 7 decimal places is 0, which is pretty good for your approximation.
If you need different behavior you should write your own sine function.
If you use float or double in math operations you will never have exact results.
The reason is that in a computer everything is stored as a power of 2. This does not translate exactly to our decimal number system. (An example is that there is n o representation in base 2 of 0.1)
In addition float and double are 64 bits at least on some compilers and platforms. (I think - somebody correct me on that if needed). This will cause some rounding errors for either very large values or for very small values (0.0000000000xxx)
In order to get exact results you are going to need some big integer library.
As written in the comments to the question above see the site ...
http://docs.sun.com/source/806-3568/ncg_goldberg.html
double cut(double value, double cutoff=1e-7) {
return (abs(value) > cutoff)*value;
}
this will zero values below threshold, use it like this cut(sin(Pi))
More significant figures might help. My C compiler (gcc) uses the constant 3.14159265358979323846 for M_PI in "math.h". Other than that, there aren't many options. Creating your own function to validate the answer (as described in another answer to your question) is probably the best idea.
You know, just for the mathematical correctness out there: sin(3.14159265) ins't zero. It's approximately zero, which is exactly what the program is telling you. For calculations, this number ought to give you a good result. For displaying, it sucks, so whenever you print a float, make sure to format the number.
I don't really think that there are any float mechanics in the work here... it's just simple math.
About the code though, be careful... doesn't make your code give the wrong result by making the approximations before the display, just display the information the right way.

Best way to store currency values in C++

I know that a float isn't appropriate to store currency values because of rounding errors. Is there a standard way to represent money in C++?
I've looked in the boost library and found nothing about it. In java, it seems that BigInteger is the way but I couldn't find an equivalent in C++. I could write my own money class, but prefer not to do so if there is something tested.
Don't store it just as cents, since you'll accumulate errors when multiplying for taxes and interest pretty quickly. At the very least, keep an extra two significant digits: $12.45 would be stored as 124,500. If you keep it in a signed 32 bit integer, you'll have $200,000 to work with (positive or negative). If you need bigger numbers or more precision, a signed 64 bit integer will likely give you all the space you'll need for a long time.
It might be of some help to wrap this value in a class, to give you one place for creating these values, doing arithmetic on them, and formatting them for display. This would also give you a central place to carry around which currency it being stored (USD, CAD, EURO, etc).
Having dealt with this in actual financial systems, I can tell you you probably want to use a number with at least 6 decimal places of precision (assuming USD). Hopefully since you're talking about currency values you won't go way out of whack here. There are proposals for adding decimal types to C++, but I don't know of any that are actually out there yet.
The best native C++ type to use here would be long double.
The problem with other approaches that simply use an int is that you have to store more than just your cents. Often financial transactions are multiplied by non-integer values and that's going to get you in trouble since $100.25 translated to 10025 * 0.000123523 (e.g. APR) is going cause problems. You're going to eventually end up in floating point land and the conversions are going to cost you a lot.
Now the problem doesn't happen in most simple situations. I'll give you a precise example:
Given several thousand currency values, if you multiply each by a percentage and then add them up, you will end up with a different number than if you had multiplied the total by that percentage if you do not keep enough decimal places. Now this might work in some situations, but you'll often be several pennies off pretty quickly. In my general experience making sure you keep a precision of up to 6 decimal places (making sure that the remaining precision is available for the whole number part).
Also understand that it doesn't matter what type you store it with if you do math in a less precise fashion. If your math is being done in single precision land, then it doesn't matter if you're storing it in double precision. Your precision will be correct to the least precise calculation.
Now that said, if you do no math other than simple addition or subtraction and then store the number then you'll be fine, but as soon as anything more complex than that shows up, you're going to be in trouble.
Look in to the relatively recent Intelr Decimal Floating-Point Math Library. It's specifically for finance applications and implements some of the new standards for binary floating point arithmetic (IEEE 754r).
The biggest issue is rounding itself!
19% of 42,50 € = 8,075 €. Due to the German rules for rounding this is 8,08 €. The problem is, that (at least on my machine) 8,075 can't be represented as double. Even if I change the variable in the debugger to this value, I end up with 8,0749999....
And this is where my rounding function (and any other on floating point logic that I can think of) fails, since it produces 8,07 €. The significant digit is 4 and so the value is rounded down. And that is plain wrong and you can't do anything about it unless you avoid using floating point values wherever possible.
It works great if you represent 42,50 € as Integer 42500000.
42500000 * 19 / 100 = 8075000. Now you can apply the rounding rule above 8080000. This can easily be transformed to a currency value for display reasons. 8,08 €.
But I would always wrap that up in a class.
I would suggest that you keep a variable for the number of cents instead of dollars. That should remove the rounding errors. Displaying it in the standards dollars/cents format should be a view concern.
You can try decimal data type:
https://github.com/vpiotr/decimal_for_cpp
Designed to store money-oriented values (money balance, currency rate, interest rate), user-defined precision. Up to 19 digits.
It's header-only solution for C++.
You say you've looked in the boost library and found nothing about there.
But there you have multiprecision/cpp_dec_float which says:
The radix of this type is 10. As a result it can behave subtly differently from base-2 types.
So if you're already using Boost, this should be good to currency values and operations, as its base 10 number and 50 or 100 digits precision (a lot).
See:
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_dec_float.hpp>
int main()
{
float bogus = 1.0 / 3.0;
boost::multiprecision::cpp_dec_float_50 correct = 1.0 / 3.0;
std::cout << std::setprecision(16) << std::fixed
<< "float: " << bogus << std::endl
<< "cpp_dec_float: " << correct << std::endl;
return 0;
}
Output:
float: 0.3333333432674408
cpp_dec_float: 0.3333333333333333
*I'm not saying float (base 2) is bad and decimal (base 10) is good. They just behave differently...
** I know this is an old post and boost::multiprecision was introduced in 2013, so wanted to remark it here.
Know YOUR range of data.
A float is only good for 6 to 7 digits of precision, so that means a max of about +-9999.99 without rounding. It is useless for most financial applications.
A double is good for 13 digits, thus: +-99,999,999,999.99, Still be careful when using large numbers. Recognize the subtracting two similar results strips away much of the precision (See a book on Numerical Analysis for potential problems).
32 bit integer is good to +-2Billion (scaling to pennies will drop 2 decimal places)
64 bit integer will handle any money, but again, be careful when converting, and multiplying by various rates in your app that might be floats/doubles.
The key is to understand your problem domain. What legal requirements do you have for accuracy? How will you display the values? How often will conversion take place? Do you need internationalization? Make sure you can answer these questions before you make your decision.
Whatever type you do decide on, I would recommend wrapping it up in a "typedef" so you can change it at a different time.
It depends on your business requirements with regards to rounding. The safest way is to store an integer with the required precision and know when/how to apply rounding.
Store the dollar and cent amount as two separate integers.
Integers, always--store it as cents (or whatever your lowest currency is where you are programming for.) The problem is that no matter what you do with floating point someday you'll find a situation where the calculation will differ if you do it in floating point. Rounding at the last minute is not the answer as real currency calculations are rounded as they go.
You can't avoid the problem by changing the order of operations, either--this fails when you have a percentage that leaves you without a proper binary representation. Accountants will freak if you are off by a single penny.
I would recommend using a long int to store the currency in the smallest denomination (for example, American money would be cents), if a decimal based currency is being used.
Very important: be sure to name all of your currency values according to what they actually contain. (Example: account_balance_cents) This will avoid a lot of problems down the line.
(Another example where this comes up is percentages. Never name a value "XXX_percent" when it actually contains a ratio not multiplied by a hundred.)
The solution is simple, store to whatever accuracy is required, as a shifted integer. But when reading in convert to a double float, so that calculations suffer fewer rounding errors. Then when storing in the database multiply to whatever integer accuracy is needed, but before truncating as an integer add +/- 1/10 to compensate for truncation errors, or +/- 51/100 to round.
Easy peasy.
The GMP library has "bignum" implementations that you can use for arbitrary sized integer calculations needed for dealing with money. See the documentation for mpz_class (warning: this is horribly incomplete though, full range of arithmetic operators are provided).
One option is to store $10.01 as 1001, and do all calculations in pennies, dividing by 100D when you display the values.
Or, use floats, and only round at the last possible moment.
Often the problems can be mitigated by changing order of operations.
Instead of value * .10 for a 10% discount, use (value * 10)/100, which will help significantly. (remember .1 is a repeating binary)
I'd use signed long for 32-bit and signed long long for 64-bit. This will give you maximum storage capacity for the underlying quantity itself. I would then develop two custom manipulators. One that converts that quantity based on exchange rates, and one that formats that quantity into your currency of choice. You can develop more manipulators for various financial operations / and rules.
This is a very old post, but I figured I update it a little since it's been a while and things have changed. I have posted some code below which represents the best way I have been able to represent money using the long long integer data type in the C programming language.
#include <stdio.h>
int main()
{
// make BIG money from cents and dollars
signed long long int cents = 0;
signed long long int dollars = 0;
// get the amount of cents
printf("Enter the amount of cents: ");
scanf("%lld", &cents);
// get the amount of dollars
printf("Enter the amount of dollars: ");
scanf("%lld", &dollars);
// calculate the amount of dollars
long long int totalDollars = dollars + (cents / 100);
// calculate the amount of cents
long long int totalCents = cents % 100;
// print the amount of dollars and cents
printf("The total amount is: %lld dollars and %lld cents\n", totalDollars, totalCents);
}
As other answers have pointed out, you should either:
Use an integer type to store whole units of your currency (ex: $1) and fractional units (ex: 10 cents) separately.
Use a base 10 decimal data type that can exactly represent real decimal numbers such as 0.1. This is important since financial calculations are based on a base 10 number system.
The choice will depend on the problem you are trying to solve. For example, if you only need to add or subtract currency values then the integer approach might be sensible. If you are building a more complex system dealing with financial securities then the decimal data type approach may be more appropriate.
As another answer points out, Boost provides a base 10 floating point number type that serves as a drop-in replacement for the native C++ floating-point types, but with much greater precision. This might be convenient to use if your project already uses other Boost libraries.
The following example shows how to properly use this decimal type:
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
using namespace std;
using namespace boost::multiprecision;
int main() {
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::max_digits10) << std::endl;
double d1 = 1.0 / 10.0;
cpp_dec_float_50 dec_incorrect = 1.0 / 10.0; // Incorrect! We are constructing our decimal data type from the binary representation of the double value of 1.0 / 10.0
cpp_dec_float_50 dec_correct(cpp_dec_float_50(1.0) / 10.0);
cpp_dec_float_50 dec_correct2("0.1"); // Constructing from a decimal digit string.
std::cout << d1 << std::endl; // 0.1000000000000000055511151231257827021181583404541015625
std::cout << dec_incorrect << std::endl; // 0.1000000000000000055511151231257827021181583404541015625
std::cout << dec_correct << std::endl; // 0.1
std::cout << dec_correct2 << std::endl; // 0.1
return 0;
}
Notice how even if we define a decimal data type but construct it from a binary representation of a double, then we will not obtain the precision that we expect. In the example above, both the double d1 and the cpp_dec_float_50 dec_incorrect are the same because of this. Notice how they are both "correct" to about 17 decimal places which is what we would expect of a double in a 64-bit system.
Finally, note that the boost multiprecision library can be significantly slower than the fastest high precision implementations available. This becomes evident at high digit counts (about 50+); at low digit counts the Boost implementation can be comparable other, faster implementations.
Sources:
https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/fp_eg/floatbuiltinctor.html
https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/fp_eg/caveats.html
Our financial institution uses "double". Since we're a "fixed income" shop, we have lots of nasty complicated algorithms that use double anyway. The trick is to be sure that your end-user presentation does not overstep the precision of double. For example, when we have a list of trades with a total in trillions of dollars, we got to be sure that we don't print garbage due to rounding issues.
go ahead and write you own money (http://junit.sourceforge.net/doc/testinfected/testing.htm) or currency () class (depending on what you need). and test it.