# SumBigDecimalHex – CodeJava
Task Input data fits into BigDecimal data type There are decimal and hexadecimal numbers in input Hexadecimal numbers has 0x prefix, so for example 0xbsc equals 11·10⁻¹² (mantissa and exponent are integers) Input is case insensitive Class should be named SumBigDecimalHex Solution This is the hardest (and last) modification for this homework. Let’s modify our SumDoubleHex parseNumber method. This is what it looks now static double parseNumber(StringBuilder number) { if (!number.isEmpty()) { String numberString = number.toString(); if ( numberString.startsWith("0x") || [cut: 844 characters, first 573 kept]

`CTRL K`

# SumBigDecimalHex

# Task

- Input data fits into BigDecimal data type
- There are decimal and hexadecimal numbers in input
- Hexadecimal numbers has `0x` prefix, so for example `0xbsc` equals `11·10⁻¹²` (mantissa and exponent are integers)
- Input is case insensitive
- Class should be named `SumBigDecimalHex`

## Solution

This is the hardest (and last) modification for this homework.

Let’s modify our `SumDoubleHex` `parseNumber` method. This is what it looks now

    static double parseNumber(StringBuilder number) {
        if (!number.isEmpty()) {
            String numberString = number.toString();
            if (
                numberString.startsWith("0x") || numberString.startsWith("0X")
            ) {
                if (numberString.contains(".")) {
                    return Double.parseDouble(numberString);
                }
                return Long.parseLong(numberString.substring(2), 16);
            } else {
                return Double.parseDouble(numberString);
            }
        } else {
            return 0;
        }
    }

Let’s make some small changes:

Firstly, let’s change the output data type to `BigDecimal`. So we will change this line

    static double parseNumber(StringBuilder number) {

to this

    static BigDecimal parseNumber(StringBuilder number) {

Also let’s change this line from the parsing of a decimal number option

    return Double.parseDouble(numberString);

to

    return new BigDecimal(numberString);

We will change this line

    return 0;

to

    return BigDecimal.ZERO;

as we did almost the same thing for `SumBigIntegerOctal` modification.

Also let’s change our `numberString` to lowercase letters just for convenience

    String numberString = number.toString().toLowerCase();

Note

Here we are using `String.toLowerCase()` method that converts all the characters to lower case.

So our code will currently look like this

    static BigDecimal parseNumber(StringBuilder number) {
        if (!number.isEmpty()) {
            String numberString = number.toString().toLowerCase(); // toLowerCase() added
            if (numberString.startsWith("0x")) {
                numberString = numberString.substring(2);
                if ( /* numberString has "s" in it  */ ) {
                    /* somehow parse number */
                }
                /* somehow parse number */
            } else {
                return new BigDecimal(numberString);
            }
        } else {
            return BigDecimal.ZERO;
        }
    }

Note

Notice, that we no longer need to check for `numberString` to begin with `"0X"`. Since there can’t be an upper case letter in the `numberString` after converting all of its letters to lower case.

Note

Also in this line

    numberString = numberString.substring(2);

we strip off first two symbols (`0x`) in order for correct parsing later.

Let’s solve our “comments” one-by-one.

The easiest is to understand if there is an `"s"` in `numberString`. We can do so using `String.contains(CharSequence s)` that returns true if and only if this string contains the specified sequence of char values. In our case the sequence of values will be `"s"`.

Let’s apply this logic to our method

    static BigDecimal parseNumber(StringBuilder number) {
        if (!number.isEmpty()) {
            String numberString = number.toString().toLowerCase();
            if (numberString.startsWith("0x")) {
                numberString = numberString.substring(2);
                if (numberString.contains("s")) { // <--
                    /* somehow parse number */
                }
                /* somehow parse number */
            } else {
                return new BigDecimal(numberString);
            }
        } else {
            return BigDecimal.ZERO;
        }
    }

Note

Again, we are not checking for upper case `"S"`, since there are no upper case letters in `numberString` because we used `.toLowerCase()`.

Okay, now let’s parse our number if it doesn’t contain `"s"`. It’s actually very simple. First we need to convert it to `BigInteger` and then pass the result to `BigDecimal`. It will look like this

    // using 16 to convert from hexadecimal to decimal
    // and only then passing to BigDecimal
    return new BigDecimal(new BigInteger(numberString, 16));

Important

Here, we don’t assign `BigInteger` object to any variable so it is used only for conversion from hexadecimal to decimal. After it’s value is passed to `BigDecimal` a garbage collector can come and destroy it, since there is no way to access it anymore.

We have only one “unsolved comment” left, but it’s going to require a bit of theory. So basically `s` splits our number in two parts: everything on the left is called a mantissa and on the right is exponent. So the form is basically the following

0 x{mantissa}s{exponent} 0x\{mantissa\}s\{exponent\} 0x{mantissa}s{exponent}

In order to get the number we will first need to convert each part from hexadecimal to decimal. Exponent represents decimal places. For example `0xABs02`: `AB` in hex equals 171 in decimal, `02` means 2 decimal places, so we shift point (`.`) 2 places left and get 1.71. Mathematically we can shift a point (`.`) by multiplying 10 with some power (in our case exponent). But to shift left we need to first negate the exponent so the point (`.`) shifts left (not right).

So the formula is

mantissa⋅10−exponent mantissa \cdot 10^{-exponent} mantissa⋅10−exponent

Okay, we are done with theory, but how can we implement it in our code.

First of all we need somehow to split our `numberString` by `"s"`. To do that we need to get the index at which `"s"` in placed. To do that we can use `String.indexOf(char ch)` method that returns the index of the first occurrence of the specified character (in our case `"s"`). Okay, then using `String.substring()` we can split into two parts. Here’s what it’s gonna look like

    int indexOfS = numberString.indexOf('s');

    // all characters before 's', without including 's' itself
    String mantissaHexString = numberString.substring(0, indexOfS);

    // all characters after 's', without including 's' itself
    String exponentHexString = numberString.substring(indexOfS + 1);

Note

Note, that we use `'s'` (not `"s"`) in `indexOf` method. That’s because it uses `char` data type as its argument, but `"s"` is a string. So we need single quotes in order to represent `char`.

Note

When extracting exponent we can use only one argument (`indexOfS + 1`), because it will automatically go to the end of the string itself.

Okay, now that we have `mantissaHexString` and `exponentHexString` we just need to convert them into decimal. That we know how to do using `BigInteger` with base specifier.

    BigInteger mantissa = new BigInteger(mantissaHexString, 16);
    BigInteger exponent = new BigInteger(exponentHexString, 16);

Okay, one thing left is to use the formula that we got

mantissa⋅10−exponent mantissa \cdot 10^{-exponent} mantissa⋅10−exponent

I will write the solution first and explain it right after

    return new BigDecimal(mantissa).scaleByPowerOfTen(exponent.negate().intValueExact());

Here we are using `BigDecimal.scaleByPowerOfTen(int n)` method to basically multiply by 10−exponent 10^{-exponent}10−exponent. Then we use `BigInteger.negate()` to basically multiply by -1. And finally we use `BigInteger.intValueExact()` to get the integer value. We do that because `scaleByPowerOfTen` method recieves integer argument (not `BigInteger`).

So our method will look like this

    static BigDecimal parseNumber(StringBuilder number) {
        if (!number.isEmpty()) {
            String numberString = number.toString().toLowerCase();
            if (numberString.startsWith("0x")) {
                numberString = numberString.substring(2);
                if (numberString.contains("s")) {
                    int indexOfS = numberString.indexOf('s');

                    String mantissaHexString = numberString.substring(0, indexOfS);
                    String exponentHexString = numberString.substring(indexOfS + 1);

                    BigInteger mantissa = new BigInteger(mantissaHexString, 16);
                    BigInteger exponent = new BigInteger(exponentHexString, 16);

                    return new BigDecimal(mantissa).scaleByPowerOfTen(exponent.negate().intValueExact());
                }
                return new BigDecimal(new BigInteger(numberString, 16));
            } else {
                return new BigDecimal(numberString);
            }
        } else {
            return BigDecimal.ZERO;
        }
    }

Okay, now let’s change `main` method accordingly. Let’s take `main` method from `SumBigIntegerOctal` modification. Here’s what it looks like now

    public static void main(String[] args) {
        BigInteger sum = new BigInteger("0");
        for (String argument : args) {
            StringBuilder number = new StringBuilder();
            for (char c : argument.toCharArray()) {
                if (!Character.isWhitespace(c)) {
                    number.append(c);
                } else {
                    sum = sum.add(parseNumber(number));
                    number = new StringBuilder();
                }
            }

            sum = sum.add(parseNumber(number));
        }

        System.out.println(sum);
    }

All we need to do is to replace the sum type from `BigInteger` to `BigDecimal`. So full code will look like this

    // SumBigDecimalHex.java

    import java.math.BigDecimal;
    import java.math.BigInteger;

    public class SumBigDecimalHex {
      public static void main(String[] args) {
          BigDecimal sum = new BigDecimal("0");
          for (String argument : args) {
              StringBuilder number = new StringBuilder();
              for (char c : argument.toCharArray()) {
                  if (!Character.isWhitespace(c)) {
                      number.append(c);
                  } else {
                      sum = sum.add(parseNumber(number));
                      number = new StringBuilder();
                  }
              }

              sum = sum.add(parseNumber(number));
          }

          System.out.println(sum);
      }

      static BigDecimal parseNumber(StringBuilder number) {
          if (!number.isEmpty()) {
              String numberString = number.toString().toLowerCase();
              if (numberString.startsWith("0x")) {
                  numberString = numberString.substring(2);
                  if (numberString.contains("s")) {
                      int indexOfS = numberString.indexOf('s');

                      String mantissaHexString = numberString.substring(0, indexOfS);
                      String exponentHexString = numberString.substring(indexOfS + 1);

                      BigInteger mantissa = new BigInteger(mantissaHexString, 16);
                      BigInteger exponent = new BigInteger(exponentHexString, 16);

                      return new BigDecimal(mantissa).scaleByPowerOfTen(exponent.negate().intValueExact());
                  }
                  return new BigDecimal(new BigInteger(numberString, 16));
              } else {
                  return new BigDecimal(numberString);
              }
          } else {
              return BigDecimal.ZERO;
          }
      }
    }

This code works correctly and passes all the tests!