update
All checks were successful
Deploy / deploy (push) Successful in 17s

This commit is contained in:
2026-04-22 08:46:19 +03:00
parent 7e5b8ade88
commit 77165a7999
26 changed files with 3156 additions and 3 deletions

View File

@@ -0,0 +1,52 @@
// 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;
}
}
}

View File

@@ -0,0 +1,322 @@
---
title: SumBigDecimalHex
weight: 6
---
# Task
- Input data fits into [BigDecimal](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html) 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
```java
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
```java
static double parseNumber(StringBuilder number) {
```
to this
```java
static BigDecimal parseNumber(StringBuilder number) {
```
Also let's change this line from the parsing of a decimal number option
```java
return Double.parseDouble(numberString);
```
to
```java
return new BigDecimal(numberString);
```
We will change this line
```java
return 0;
```
to
```java
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()`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#toLowerCase--) method that converts all the characters to lower case.
So our code will currently look like this
```java
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
> ```java
> 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)`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#contains-java.lang.CharSequence-) 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
```java
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
```java
// 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
$$
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 \cdot 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)`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#indexOf-int-) method that returns the index of the first occurrence of the specified character (in our case `"s"`). Okay, then using [`String.substring()`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#substring-int-) we can split into two parts. Here's what it's gonna look like
```java
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`](https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html) 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.
```java
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 \cdot 10^{-exponent}
$$
I will write the solution first and explain it right after
```java
return new BigDecimal(mantissa).scaleByPowerOfTen(exponent.negate().intValueExact());
```
Here we are using [`BigDecimal.scaleByPowerOfTen(int n)`](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html#scaleByPowerOfTen-int-) method to basically multiply by \(10^{-exponent}\). Then we use [`BigInteger.negate()`](https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html#negate--) to basically multiply by -1. And finally we use [`BigInteger.intValueExact()`](https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html#intValueExact--) to get the integer value. We do that because `scaleByPowerOfTen` method recieves integer argument (not `BigInteger`).
So our method will look like this
```java
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
```java
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
```java
// 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!

View File

@@ -2,3 +2,7 @@
title: Summing Up
weight: 6
---
Here I just wanted to apply some of the best practises to improve our code a little better.