How to make money with Java and C++ : IEEE 754 and the real life : 0.1+0.2=0.3 yes, but how?
Published: 2022-06-27 13:57:11

It's been a while since [we've started](https://dev.to/hexfloor/how-to-make-money-with-java-and-c-ieee-754-and-the-real-life-ordering-zeros-2bcn), it is what it is.

Let's just go straight to the point and see why should we handle money with care.
Here and after Java stands for Java 17 and C++ stands for C++ 20, if not specified differently, I will use w3schools compiler both for [Java](https://www.w3schools.com/java/tryjava.asp?filename=demo_compiler) and [C++](https://www.w3schools.com/cpp/trycpp.asp?filename=demo_compiler)

The good start in understanding the problem is following the [link](https://0.30000000000000004.com/)

## C++ : 0.1d + 0.2d != 0.3d

```
#include <iostream>
#include <limits>
typedef std::numeric_limits< double > dl;

int main() {
  std::cout.precision(dl::max_digits10);
  std::cout<<0.1d<<std::endl;
  std::cout<<0.2d<<std::endl;
  std::cout<<0.3d<<std::endl;
  std::cout<<0.1d + 0.2d<<std::endl;
  std::cout<<(0.1d + 0.2d == 0.3d)<<std::endl;
  return 0;
}
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swhuzhmw08fafpjie6g8.png)
 

That is clear that following the [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) the in memory representation is an approximation. Though it's not guaranteed to have always the same approximation as you might have expected.

## Java : 0.1d + 0.2d != 0.3d

Let's check for the same in Java : 

```
public class Main {
  public static void main(String[] args) {
  	final String DOUBLE_FORMAT = "%.17f";
  	System.out.println(String.format(DOUBLE_FORMAT, 0.1d));
    System.out.println(String.format(DOUBLE_FORMAT, 0.2d));
    System.out.println(String.format(DOUBLE_FORMAT, 0.3d));
    System.out.println(String.format(DOUBLE_FORMAT, 0.1d + 0.2d));
    System.out.println(0.1d + 0.2d == 0.3d);
  }
}

```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwzi3zp26ca8r99o8ec5.png)
Thus we can't use double represent money in Java either.

## Reduction of summation error

If you are looking to get more consistent results when adding floating point numbers you may check on the [Kahan summation algorithm](https://en.wikipedia.org/wiki/Kahan_summation_algorithm)
Otherwise to solve our problem as is we need something simpler, and the name for it is [decimal data type support](https://en.wikipedia.org/wiki/Decimal_data_type).
In fact we may represent `0.1` as `1` shifted by 1 position to the right, same for `0.2` and `0.3` and then it's simple to add `0.1` and `0.2`, we are just summing up `1` and `2` and shift the result to the right. In fact we represent our decimal values as integers with a shift. More details following the link to the [decimal 64](https://en.wikipedia.org/wiki/Decimal64_floating-point_format)

Kindly note that when working with decimal types the assignment happens from string to decimal, not from floating point type.

## C++ : boost multiprecision 0.1 + 0.2 == 0.3
[boost multiprecision] (https://www.boost.org/doc/libs/1_73_0/libs/multiprecision/doc/html/index.html)

Using the decimal types we get that `0.1 + 0.2 == 0.3`

```
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
using boost::multiprecision::cpp_dec_float_50;

int main() {
  cpp_dec_float_50 d01("0.1");
  cpp_dec_float_50 d02("0.2");
  cpp_dec_float_50 d03("0.3");
  std::cout<<std::fixed<<std::setprecision(50)<<d01<<std::endl;
  std::cout<<std::fixed<<std::setprecision(50)<<d02<<std::endl;
  std::cout<<std::fixed<<std::setprecision(50)<<d03<<std::endl;
  std::cout<<std::fixed<<std::setprecision(50)<<(d01 + d02)<<std::endl;
  std::cout<<std::fixed<<std::setprecision(50)<<(d01 + d02 == d03)<<std::endl;
  return 0;
}

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1t0yewccjzapcjiwdum.png)
 

Multiplication is straight forward as well

```
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
using boost::multiprecision::cpp_dec_float_50;

int main() {
  cpp_dec_float_50 d01("0.1");
  cpp_dec_float_50 d02("0.2");
  std::cout<<std::fixed<<std::setprecision(50)<<d01 * d02<<std::endl;
  return 0;
}

```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xhj86rnlekhsssu0gr3a.png)

What about the division ? By default it works the way you would have expected.

```
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
using boost::multiprecision::cpp_dec_float_50;

int main() {
  cpp_dec_float_50 d1("1");
  cpp_dec_float_50 d2("2");
  cpp_dec_float_50 d3("3");
  std::cout<<std::fixed<<std::setprecision(50)<<d1 / d2<<std::endl;
  std::cout<<std::fixed<<std::setprecision(50)<<d1 / d3<<std::endl;
  std::cout<<std::fixed<<std::setprecision(50)<<d2 / d3<<std::endl;
  return 0;
}

```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1jkndv9b45ual0nqyymg.png)
 

## Java : Big Decimal 0.1 + 0.2 == 0.3
[Big Decimal](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html)

The summation with BigDecimal : 

```
import java.math.BigDecimal;
public class Main {
  public static void main(String[] args) {
    final String DOUBLE_FORMAT = "%.17f";
    BigDecimal d01 = new BigDecimal("0.1");
    BigDecimal d02 = new BigDecimal("0.2");
    BigDecimal d03 = new BigDecimal("0.3");
    System.out.println(String.format(DOUBLE_FORMAT, d01));
    System.out.println(String.format(DOUBLE_FORMAT, d02));
    System.out.println(String.format(DOUBLE_FORMAT, d03));
    System.out.println(String.format(DOUBLE_FORMAT, d01.add(d02)));
    System.out.println(d01.add(d02).equals(d03));
  }
}
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jn3ms96868j2xsh8wnw.png)

and the multiplication : 

```
import java.math.BigDecimal;
public class Main {
  public static void main(String[] args) {
    final String DOUBLE_FORMAT = "%.17f";
    BigDecimal d01 = new BigDecimal("0.1");
    BigDecimal d02 = new BigDecimal("0.2");
    System.out.println(String.format(DOUBLE_FORMAT, d01.multiply(d02)));
  }
}

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0hd5kc8xvryy1spw9y8b.png)
 
work as you might have expected, for the division there is a particularity, either a result of division must be representable in a finite decimal way or we need to pass a [MathContext](https://docs.oracle.com/javase/7/docs/api/java/math/MathContext.html)

```
import java.math.BigDecimal;
public class Main {
  public static void main(String[] args) {
    final String DOUBLE_FORMAT = "%.17f";
    BigDecimal d1 = new BigDecimal("1");
    BigDecimal d2 = new BigDecimal("2");
    BigDecimal d3 = new BigDecimal("3");
    System.out.println(String.format(DOUBLE_FORMAT, d1.divide(d2)));
  }
}

```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/omtkmmspueepiugv5ysr.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/htili9t7vlw58g51u6ax.png)

```
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
public class Main {
  public static void main(String[] args) {
    final String DOUBLE_FORMAT = "%.17f";
    BigDecimal d1 = new BigDecimal("1");
    BigDecimal d2 = new BigDecimal("2");
    BigDecimal d3 = new BigDecimal("3");
    System.out.println(d1.divide(d3, MathContext.DECIMAL32));
    System.out.println(d1.divide(d3, MathContext.DECIMAL64));
	System.out.println(d1.divide(d3, MathContext.DECIMAL128));
	System.out.println(d1.divide(d3, 2, RoundingMode.HALF_EVEN));

  }
}

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tz3lcb1hiw6co4jmzttr.png)

```
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
public class Main {
  public static void main(String[] args) {
    final String DOUBLE_FORMAT = "%.17f";
    BigDecimal d1 = new BigDecimal("1");
    BigDecimal d2 = new BigDecimal("2");
    BigDecimal d3 = new BigDecimal("3");
    System.out.println(d2.divide(d3, MathContext.DECIMAL32));
    System.out.println(d2.divide(d3, MathContext.DECIMAL64));
	System.out.println(d2.divide(d3, MathContext.DECIMAL128));
	System.out.println(d2.divide(d3, 2, RoundingMode.HALF_EVEN));

  }
}

 
```
   ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vi9dpj3uou9nurpwjedj.png)

## Summary

Whenever you are working with money it's a good idea to use either integer or decimal type. It may happen that you need to write a custom decimal type for your needs, in this case the general guidelines could be the following : 

- constructor from a string (or a factory)
- internal representation as an integer with a shift (also integer)
- handling of rounding during division
 
And therefore it could be even better a idea to consider a use of a provided decimal type or a lib.
Take care.